zoukankan      html  css  js  c++  java
  • RPC 框架(附 dubbo & grpc 简例)



    HTTP 和 RPC

    在微服务体系结构中,独立部署在各个机器或容器上的服务之间,如何进行有效的通信,是一个很重要的问题,现在常用的主要是 RESTful HTTP 和 RPC

    HTTP 的优点

    • 通用性强,基本上所有框架,所有语言都支持 HTTP
    • 可读性高,URL 对资源的定义,Action 对操作的定义,Payload 的定义都比较清晰易懂
    • 可以通过各种防火墙、网关

    HTTP 的缺点

    • HTTP 协议的效率比较低(毕竟是网络第 7 层协议)
    • HTTP 协议的有效信息占比小
    • 客户度编写调用 HTTP 请求的代码并不易用

    RPC(Remote Procedure Call,远程过程调用)使客户端向服务端发请求就像调用本地函数一样

    比如客户端调用

    String message = service.sayHi("dubbo");
    

    服务端会有相应的函数被执行并返回结果给客户端

        public String sayHi(String name) {
            return "hi, " + name;
        }
    

    RPC 的优点

    • 使用 TCP 或 HTTP2.0 协议,通信效率高,有效信息占比大
    • 客户端调用 RPC 请求就像调用本地函数一样,代码比较简单,容易使用

    RPC 的缺点

    • 可读性没有 HTTP 强
    • 缺少通用性,和 HTTP 是统一的标准不同,RPC 框架的实现各不相同,有的仅支持单语言,有的支持跨语言,有的支持多种序列化协议,有的仅有一种固定的序列化协议,有的支持管理中心、服务发现、负载均衡、熔断降级等功能,有的不支持
    • 需要和特定的框架绑定使用,比较紧耦合
    • 不同的网关对 RPC 的支持可能会不够(对 TCP、HTTP2.0 的支持)

    可以看到,HTTP 和 RPC 各有千秋,通常暴露给外部用户的都是 HTTP,而当系统内部的微服务特别多,微服务之间的通信量特别大的时候,为了提高性能简化代码可以使用 RPC,但是如果微服务没有拆的很细,或是对性能要求不是很高,内部通信也可以使用 HTTP

    RPC 技术

    通常包含以下技术实现

    • 动态代理

    客户端实际上只定义了接口,具体的实现在服务端,所以需要有动态代理,当客户端调用函数的时候,将信息传递到服务端,在服务端调用真正的实现,接受它的返回给客户端

    • 序列化放序列化

    客户端需要将数据序列化,在服务端要做反序列化

    • 通信协议

    需要高效的通信协议以提高性能

    • 异常处理

    出现网络故障、服务端错误等各种异常的时候要怎么处理

    RPC 常用框架

    • dubbo

    阿里巴巴开发的 RPC 框架,支持 Java,2012 年开源,2014 年停止维护,2017 年又重新维护,后来捐给了 Apache

    dubbo 架构如下图

    https://dubbo.apache.org/zh/docs/v2.7/user/preface/architecture/

    Provider 向 Registry 注册服务,Consumer 通过 Registry 获取 Provider 服务的信息

    服务注册中心,服务提供者,服务消费者三者之间均为长连接

    Consumer 向 Provider (可以配多个 Provider 实例)发请求时,可以自动实现负载均衡等算法

    监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示

    注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表

    注册中心和监控中心都是可选的,服务消费者可以直连服务提供者

    健壮性和伸缩性

    底层协议可以是:dubbo、rest、http、hessian、redis、thrift、gRPC、memcached、rmi、webservice,默认是 dubbo(采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,不适合传送大数据量的服务)
    https://dubbo.apache.org/zh/docs/v2.7/user/references/xml/dubbo-registry/
    https://dubbo.apache.org/zh/docs/v2.7/user/references/protocol/
    https://dubbo.apache.org/zh/docs/v2.7/user/perf-test/

    注册中心可以是:dubbo, nacos, multicast, zookeeper, redis, consul, sofa, etcd,推荐使用 zookeeper
    https://dubbo.apache.org/zh/docs/v2.7/user/references/xml/dubbo-registry/

    2.7.5 引入了基于 AK/SK 机制的认证鉴权机制,并且引入了鉴权服务中心,主要原理是消费端在请求需要鉴权的服务时,会通过 SK、请求元数据、时间戳、参数等信息来生成对应的请求签名,通过 Dubbo 的 Attahcment 机制携带到对端进行验签,验签通过才进行业务逻辑处理

    dubbo 可以直接和 SpringBoot 集成

    各种用法示例
    https://dubbo.apache.org/zh/docs/v2.7/user/examples/

    • gRPC

    Google 开发的 RPC 框架

    支持多种语言,并且 Consumer 和 Provider 之间可以跨语言

    使用 proto3 定义接口后可以生成不同语言的源文件

    没有注册服务中心、负载均衡、熔断降级等功能

    默认使用 protocol buffers 作为序列化反序列化机制,protocol buffers 的压缩速度快,压缩率高

    支持 SSL/TLS、OAuth 2.0 等认证授权协议

    使用 HTTP2.0 作为通信协议,HTTP2.0 采用新的数据格式、新的 Header 压缩算法、服务端推送、链接共享等机制,性能大幅度提升,但现在支持的组件可能不多,比如如果要通过 Nginx 它可能不认 HTTP2.0 只把它当做 TCP 消息对待

    • Motan

    微博开发的 RPC 框架,用 Java 实现,可以和 SpringBoot 集成

    https://github.com/weibocom/motan

    无需多少额外代码即可实现
    支持 Consul、Zookeeper 作为服务发现中心
    支持负载均衡
    为高负载场景做了优化
    支持同步调用和异步调用
    支持 Java、Go、PHP 等多语言

    • rpcx

    微博开发的,用 Go 语言开发,参考了阿里巴巴的 dubbo 和微博的 Motan

    https://github.com/smallnest/rpcx
    https://blog.rpcx.io/posts/why-did-i-develop-rpcx/
    https://doc.rpcx.io/

    性能很好,貌似比 dubbo、grpc、motan 都要好

    支持原生 Go 函数,不需要定义 proto 文件
    支持 TCP、HTTP、KCP、QUIC 等传输协议
    支持 JSON、Protobuf、MessagePack 数据编码协议
    服务发现,支持 P2P、zookeeper、etcd、consul、mDNS 等
    容错(Fault tolerance):支持 Failover(切换)、Failfast(快速失败)、Failtry(重试)
    支持负载均衡
    支持认证授权
    支持心跳检测

    貌似还支持跨语言
    rpcx uses a binary protocol and platform-independent, which means you can develop services in other languages such as Java, python, nodejs, and you can use other prorgramming languages to invoke services developed in Go.

    • Thrift

    由 Facebook 开发的 RPC 框架,后来捐给了 Apache

    https://github.com/apache/thrift

    是一个轻量级的、跨语言的、点到点的 RPC 框架

    定义好接口后,代码生成器可以生成不同语言的代码

    从上图可以看到,Thrift 支持很多种语言、传输协议、数据协议、应用模式

    Thrift 不支持服务发现、负载均衡、熔断降级等功能

    dubbo 例子

    定义有 3 个模块的项目

        <groupId>com.example</groupId>
        <artifactId>dubbo</artifactId>
        <packaging>pom</packaging>
        <version>1.0-SNAPSHOT</version>
    
        <modules>
            <module>dubbo-example-interface</module>
            <module>dubbo-example-consumer</module>
            <module>dubbo-example-provider</module>
        </modules>
    

    interface 只定义了一个接口

    package com.example.dubbo.interfaces;
    
    public interface GreetingService {
        String sayHi(String name);
    }
    

    maven install 编译安装 interface

    provider 实现了接口

        <parent>
            <groupId>com.example</groupId>
            <artifactId>dubbo</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../pom.xml</relativePath>
        </parent>
        
        <artifactId>dubbo-example-provider</artifactId>
        <packaging>jar</packaging>
        <description>Demo project for dubbo</description>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo</artifactId>
                <version>2.7.8</version>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-dependencies-zookeeper</artifactId>
                <version>2.7.8</version>
                <type>pom</type>
            </dependency>
            
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>dubbo-example-interface</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>            
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    public class GreetingServiceImpl implements GreetingService {
        @Override
        public String sayHi(String name) {
            System.out.println("receive msg " + name);
            return "hi, " + name;
        }
    }
    
    public class Provider {
        private static String zookeeperHost = System.getProperty("zookeeper.address", "localhost");
    
        public static void main(String[] args) throws Exception {
            ServiceConfig<GreetingService> service = new ServiceConfig<>();
            service.setApplication(new ApplicationConfig("first-dubbo-provider"));
            service.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
            service.setInterface(GreetingService.class);
            service.setRef(new GreetingServiceImpl());
            service.export();
    
            System.out.println("dubbo service started");
            new CountDownLatch(1).await();
        }
    }
    

    consumer 调用接口

        <parent>
            <groupId>com.example</groupId>
            <artifactId>dubbo</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../pom.xml</relativePath>
        </parent>
        
        <artifactId>dubbo-example-consumer</artifactId>
        <packaging>jar</packaging>
        <description>Demo project for dubbo</description>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo</artifactId>
                <version>2.7.8</version>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-dependencies-zookeeper</artifactId>
                <version>2.7.8</version>
                <type>pom</type>
            </dependency>
            
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>dubbo-example-interface</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
        
        <build>
            <plugins>            
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    public class Consumer {
        private static String zookeeperHost = System.getProperty("zookeeper.address", "localhost");
    
        public static void main(String[] args) {
            ReferenceConfig<GreetingService> reference = new ReferenceConfig<>();
            reference.setApplication(new ApplicationConfig("first-dubbo-consumer"));
            reference.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
            reference.setInterface(GreetingService.class);
            GreetingService service = reference.get();
            String message = service.sayHi("dubbo");
            System.out.println(message);
        }
    }
    

    运行后看到 consumer 打出 hi, dubbo

    gRPC 例子

    定义有 4 个模块的项目

        <modules>
            <module>grpc-example-proto</module>
            <module>grpc-example-interfaces</module>
            <module>grpc-example-client</module>
            <module>grpc-example-server</module>
        </modules>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>io.grpc</groupId>
                    <artifactId>grpc-netty-shaded</artifactId>
                    <version>1.35.0</version>
                </dependency>
                <dependency>
                    <groupId>io.grpc</groupId>
                    <artifactId>grpc-protobuf</artifactId>
                    <version>1.35.0</version>
                </dependency>
                <dependency>
                    <groupId>io.grpc</groupId>
                    <artifactId>grpc-stub</artifactId>
                    <version>1.35.0</version>
                </dependency>
                <dependency> <!-- necessary for Java 9+ -->
                    <groupId>org.apache.tomcat</groupId>
                    <artifactId>annotations-api</artifactId>
                    <version>6.0.53</version>
                    <scope>provided</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    

    proto 定义接口并用于生产代码

        <parent>
            <groupId>com.example</groupId>
            <artifactId>grpc</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../pom.xml</relativePath>
        </parent>
        
        <artifactId>grpc-example-proto</artifactId>
        <packaging>jar</packaging>
        <description>Demo project for grpc</description>
    
        <dependencies>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty-shaded</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <extensions>
                <extension>
                    <groupId>kr.motd.maven</groupId>
                    <artifactId>os-maven-plugin</artifactId>
                    <version>1.6.2</version>
                </extension>
            </extensions>
      
            <plugins>            
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                
                <plugin>
                    <groupId>org.xolstice.maven.plugins</groupId>
                    <artifactId>protobuf-maven-plugin</artifactId>
                    <version>0.6.1</version>
                    <configuration>
                        <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
                        <pluginId>grpc-java</pluginId>
                        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.35.0:exe:${os.detected.classifier}</pluginArtifact>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>compile-custom</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    

    在 src/main/proto 下创建 GreetingService.proto 文件,定义接口

    syntax = "proto3";
    
    
    option java_multiple_files = true; 
    option java_package = "com.example.grpc.interfaces"; 
    option java_outer_classname = "GreetingServiceProto"; 
    option objc_class_prefix = "HLW";
    
    
    package GreetingService;
    
    
    service GreetingService {
        rpc SayHi (GreetingRequest) returns (GreetingReply) {} 
    }
    
    message GreetingRequest { 
        string name = 1; 
    }
    
    message GreetingReply { 
        string message = 1; 
    } 
    

    然后执行 maven install 会生产源代码
    将 target/generated-sources/protobuf 下面的源文件都考到 interface 项目下面

    interface 的 pom 要引用 grpc

        <parent>
            <groupId>com.example</groupId>
            <artifactId>grpc</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../pom.xml</relativePath>
        </parent>
        
        <artifactId>grpc-example-interfaces</artifactId>
        <packaging>jar</packaging>
        <description>Demo project for grpc</description>
    
        <dependencies>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty-shaded</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>            
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    

    maven install 编译安装 interface

    再编写 server 实现接口

        <parent>
            <groupId>com.example</groupId>
            <artifactId>grpc</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../pom.xml</relativePath>
        </parent>
        
        <artifactId>grpc-example-server</artifactId>
        <packaging>jar</packaging>
        <description>Demo project for grpc</description>
    
        <dependencies>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty-shaded</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
            </dependency>
            
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>grpc-example-interfaces</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>            
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase  {
    
        @Override 
        public void sayHi(GreetingRequest req, StreamObserver<GreetingReply> responseObserver){ 
            GreetingReply reply = GreetingReply.newBuilder().setMessage(("Hi " + req.getName())).build(); 
            responseObserver.onNext(reply); 
            responseObserver.onCompleted(); 
        } 
    }
    
    public class GrpcServer {
    
        private static final Logger logger = Logger.getLogger(GrpcServer.class.getName());
    
        private int port = 50051; 
        private Server server;
    
        private void start() throws IOException {
            server = ServerBuilder.forPort(port) 
                                  .addService(new GreetingServiceImpl()) 
                                  .build() 
                                  .start();
    
            logger.info("Server started, listening on "+ port);
    
            Runtime.getRuntime().addShutdownHook(new Thread(){
                @Override 
                public void run(){
                    System.err.println("*** shutting down gRPC server since JVM is shutting down"); 
                    GrpcServer.this.stop(); 
                    System.err.println("*** server shut down"); 
                } 
            }); 
        }
    
        private void stop() { 
            if (server != null){ 
                server.shutdown(); 
            } 
        }
    
        private void blockUntilShutdown() throws InterruptedException { 
            if (server != null){ 
                server.awaitTermination(); 
            } 
        }
    
    
        public static void main(String[] args) throws IOException, InterruptedException {
            final GrpcServer server = new GrpcServer(); 
            server.start(); 
            server.blockUntilShutdown(); 
        }
    } 
    

    再编写 client 调用接口

        <parent>
            <groupId>com.example</groupId>
            <artifactId>grpc</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../pom.xml</relativePath>
        </parent>
        
        <artifactId>grpc-example-client</artifactId>
        <packaging>jar</packaging>
        <description>Demo project for grpc</description>
    
        <dependencies>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty-shaded</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
            </dependency>
            
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>grpc-example-interfaces</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
        </dependencies>
        
        <build>
            <plugins>            
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    public class GrpcClient {
    
        private final ManagedChannel channel; 
        private final GreetingServiceGrpc.GreetingServiceBlockingStub blockingStub; 
        private static final Logger logger = Logger.getLogger(GrpcClient.class.getName());
    
        public GrpcClient(String host, int port){ 
            channel = ManagedChannelBuilder.forAddress(host, port) 
                                           .usePlaintext() 
                                           .build();
    
            blockingStub = GreetingServiceGrpc.newBlockingStub(channel); 
        }
    
        public void shutdown() throws InterruptedException { 
            channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); 
        }
    
        public void greet(String name){ 
            GreetingRequest request = GreetingRequest.newBuilder().setName(name).build(); 
            GreetingReply response;
            
            try{ 
                response = blockingStub.sayHi(request); 
            } catch (StatusRuntimeException e) { 
                logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); 
                return;
            }
            
            logger.info("Greeting: " + response.getMessage()); 
        }
    
        public static void main(String[] args) throws InterruptedException { 
            GrpcClient client = new GrpcClient("localhost", 50051); 
            
            try{ 
                String user = "GRPC"; 
                if (args.length > 0){
                    user = args[0];
                }
                client.greet(user); 
            }finally { 
                client.shutdown(); 
            } 
        } 
    }
    


  • 相关阅读:
    django admin site配置(二)
    MyEclipse中无法将SVN检出来的项目部署到tomcat中
    遍历目录树,清理编译目录
    axis2学习, ant 构建axis2 ws
    [置顶] 2013 Multi-University Training Contest 8
    Cocos2d-x 关于在iOS平台真机测试的一些注意
    SharePoint 2013的100个新功能之社交
    路由共享上网原理
    red ant
    nginx正向代理访问百度地图API
  • 原文地址:https://www.cnblogs.com/moonlight-lin/p/14347010.html
Copyright © 2011-2022 走看看