常用的RPC架构系列---gRPC - Go语言中文社区

常用的RPC架构系列---gRPC


gRPC是谷歌的一个高性能,开源的高性能 RPC 框架,gRPC面向移动和HTTP/2设计。gRPC隐藏了底层的实现细节,包括序列化(json,xml),数据传输(TCP,HTTP,UDP),反序列化等,它可以有效地将数据中心内和跨数据中心的服务与可插拔支持进行负载均衡、跟踪、健康检查和认证。gRPC使用在移动设备上能表现更好的特性,例如更省电,更省空间。

gRPC设计理念

定义一个服务,指定其能够被远程调用的方法。在服务端实现这个接口,并运行一个gRPC服务来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。gRPC客户端和服务端都可以在这种环境中运行和交互。

file

gRPC主要使用场景

在gRPC项目中,客户端应用可以像调用本地对象一样直接调用另一台不同机器的服务端应用,更能够容易的创建分布式应用和服务。

  • 在微服务架构中有效的连接多个服务
  • 将移动设备,浏览器客户端连接到后端服务
  • 生成高效的客户端

spring boot集成gRPC

因为gRPC依赖Protocol Buffers,所以先简单看看什么是Protocol Buffers。

Protocol Buffers 简称protobuf,是一种高效,轻便,易用的结构化数据存储格式。数据存储格式使用最多的是JSON,XML,他们简单,易读,与平台,语言无关。那么既然有JSON,XML,为什么还要有protobuf。普遍认为有两种原因:

  • protobuf具有了JSON,XML格式所有有点
  • protobuf解析速度比JSON,XML快,效率高
  • protobuf序列化数据非常紧凑,简洁

1,idea安装protobuf插件。

setting-->Plugins ,搜到protobuf support,然后点击安装即可,最后重启idea

file

2,新建grpc父项目。

分别新建三个模块:grpc-lib,grpc-server(使用开源grpc-server-spring-boot-starter组件),grpc-client(使用开源grpc-client-spring-boot-starter组件)

组件官网:https://github.com/yidongnan/grpc-spring-boot-starter

因为使用父项目的pom.xml来管理,所以pom.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.grpc</groupId>
    <artifactId>grpc</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>grpc-lib</module>
        <module>grpc-server</module>
        <module>grpc-client</module>
    </modules>


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-boot.version>2.0.5.RELEASE</spring-boot.version>
        <net-devh-grpc.version>2.0.1.RELEASE</net-devh-grpc.version>

    </properties>

    <dependencyManagement>
        <dependencies>
            <!--依赖维护平台,在添加第三方依赖的时候,不需要写版本号,它能够自动帮我们挑选一个最优的版本-->
            <dependency>
                <groupId>io.spring.platform</groupId>
                <artifactId>platform-bom</artifactId>
                <version>Cairo-RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--公共grpc模块-->
            <dependency>
                <groupId>com.grpc</groupId>
                <artifactId>grpc-lib</artifactId>
                <version>${project.version}</version>
            </dependency>
            <!--核心grpc-spring-boot依赖-->
            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-client-spring-boot-starter</artifactId>
                <version>${net-devh-grpc.version}</version>
            </dependency>
            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-server-spring-boot-starter</artifactId>
                <version>${net-devh-grpc.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>
  • grpc-lib

其中grpc-lib的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>grpc</artifactId>
        <groupId>com.grpc</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>grpc-lib</artifactId>

    <properties>
        <os.plugin.version>1.6.0</os.plugin.version>
        <grpc.version>1.15.1</grpc.version>
        <protoc.version>3.6.1</protoc.version>
        <protobuf.plugin.version>0.6.1</protobuf.plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-all</artifactId>
            <version>${grpc.version}</version>
        </dependency>
    </dependencies>

    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>${os.plugin.version}</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>${protobuf.plugin.version}</version>
                <extensions>true</extensions>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                    <!--默认值-->
                    <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
                    <!--默认值-->
                    <!--<outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>-->
                    <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
                    <!--设置是否在生成java文件之前清空outputDirectory的文件,默认值为true,设置为false时也会覆盖同名文件-->
                    <clearOutputDirectory>false</clearOutputDirectory>
                    <!--更多配置信息可以查看https://www.xolstice.org/protobuf-maven-plugin/compile-mojo.html-->
                </configuration>
                <executions>
                    <execution>
                        <!--在执行mvn compile的时候会执行以下操作-->
                        <phase>compile</phase>
                        <goals>
                            <!--生成OuterClass类-->
                            <goal>compile</goal>
                            <!--生成Grpc类-->
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

在lib模块下新建proto文件夹,加入以下ptoro文件:

syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.grpc.proto.service";
service HelloService{
    rpc SayHello(HelloRequest) returns (HelloResponse){}
}
message HelloRequest{
    string username = 1;
}
message HelloResponse{
    string message = 1;
}

上面的ptoro文件中

  • syntax指定了protobuf版本为proto3。
  • option java_package:指定生成类的报名
  • option java_multiple_files有两个值,true和false。如果为true,每个message和service都会被生成为一个类。如果是false,则所有的message和service都将会是java_outer_classname的内部类
  • service HelloService:定义Rpc的Service,这里需要注意:下面的方法的传入参数和返回类型都必须是message
  • message HelloRequest:相当于请求参数,为string类型
  • message HelloResponse:相当于返回参数,为string类型。

运行protobuf插件的compile和compile-custom功能,生成java代码到src/main/java目录下。见图:

file
  • grpc-server
    grpc-server模块pom.xml文件如下:

      <project xmlns="http://maven.apache.org/POM/4.0.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <parent>
          <artifactId>grpc</artifactId>
          <groupId>com.grpc</groupId>
          <version>1.0-SNAPSHOT</version>
      </parent>
      <modelVersion>4.0.0</modelVersion>
      <artifactId>grpc-server</artifactId>
      <dependencies>
          <dependency>
              <groupId>com.grpc</groupId>
              <artifactId>grpc-lib</artifactId>
          </dependency>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter</artifactId>
          </dependency>
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-test</artifactId>
              <scope>test</scope>
          </dependency>
          <dependency>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
          </dependency>
          <dependency>
              <groupId>net.devh</groupId>
              <artifactId>grpc-server-spring-boot-starter</artifactId>
          </dependency>
      </dependencies>
    

    </project>

(1)application.yml文件:

file

说明:在使用grpc-server-spring-boot-starter组件时,可以设置 gRPC 的 host(默认:0.0.0.0) 跟 port (默认9090)

(2)HelloService类

@GrpcService(HelloServiceGrpc.class)
public class HelloService extends HelloServiceGrpc.HelloServiceImplBase {
    @Override
    public void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
        System.out.println("GRPC servier "+ request.getUsername());
        HelloResponse helloResponse = HelloResponse.newBuilder().setMessage("GRPC servier "+ request.getUsername()).build();
        responseObserver.onNext(helloResponse);
        responseObserver.onCompleted();
    }
}

这里,server端就完成了。

  • grpc-client

grpc-client模块的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>grpc</artifactId>
        <groupId>com.grpc</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>grpc-client</artifactId>
    <dependencies>
        <dependency>
            <groupId>com.grpc</groupId>
            <artifactId>grpc-lib</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-client-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
</project>

(1)application.yml文件:

file

说明:这里我没有配置指定grpc-server地址和端口,如果没有配置,那将会按照下面的方式进行解析:

  • 如果存在一个 DiscoveryClient 的 bean,这时会使用 client name 去注册中心上进行获取对应服务的 address
  • 否则 client 端将使用 localhost 和 9090 端口

(2)HelloClient类

@Service
public class HelloClient {
    @GrpcClient("grpc-server")
    private Channel serverChannel;
    public String sayHello(String username){
        return HelloServiceGrpc.newBlockingStub(serverChannel).sayHello(HelloRequest.newBuilder().setUsername(username).build()).getMessage();
    }
}

说明:@GrpcClient("grpc-server"),指定的值为grpc服务提供方名称,这里是grpc-server。

(3)HelloController类

@RestController
public class HelloController {
    @Autowired
    private HelloClient client;
    @GetMapping("/sayHello")
    public String sayHello(String username){
        return client.sayHello(username);
    } 
}

这里,client端就完成了。

3,测试

先启动server,再启动client。使用浏览器访问client端接口:http://localhost:8081/sayHello?username=张三

server端打印:

file

client端效果:

file

总结,spring boot与gRPC整合还是很简单,最重要的是版本要一致,然后对proto语法有个大致的了解。

本人水平有限,难免有错误或遗漏之处,望大家指正和谅解,提出宝贵意见,愿与之交流。

版权声明:本文来源简书,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.jianshu.com/p/761462470543
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-02 14:22:10
  • 阅读 ( 1270 )
  • 分类:架构

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢