常用的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语法有个大致的了解。

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容