• gRPC简介


    Grpc简介

    1. gRPC是一项进程间通信技术,可以用来连接、调用、操作和调试分布式异构应用程序。

    2. 在开发gRPC应用程序时,先要定义服务接口,其中应包含

      • 消费者消费服务的方式

      • 消费者能够远程调用的方法

      • 调用这些方法所使用的参数和消息格式等

    3. 在服务定义中所使用的语言叫作接口定义语言(interface definition language,IDL)。服务定义

      • 可以生成服务器端代码,也就是服务器端骨架,它通过提供低层级的通信抽象简化了服务器端的逻辑。
      • 可以生成客户端代码,也就是客户端存根,它使用抽象简化了客户端的通信,为不同的编程语言隐藏了低层级的通信
    4. 基于gPRC的生产者和消费者
      在这里插入图片描述

    5. 当调用gRPC服务时,客户端的gRPC库会使用protocol buffers,并将RPC的请求编排(marshal)为protocol buffers格式,然后将其通过HTTP/2进行发送。在服务器端,请求会被解排(unmarshal),对应的过程调用会使用protocol buffers来执行。

    6. gPRC劣势

      • 不太适合面向外部的服务。gRPC服务具有契约驱动、强类型的特点,会限制向外部暴露的服务的灵活性,同时消费者的控制权会削弱很多
      • 巨大的服务定义变更是复杂的开发流程。如果出现巨大的gRPC服务定义变更,通常需要重新生成客户端代码和服务器端代码。
      • gRPC生态系统相对较小

    开发案例

    定义服务接口

    1. 创建接口模块grpc-demo:grpc-apigrpc的版本一定要与protobuf匹配

      apply plugin: "io.spring.dependency-management"
      dependencyManagement {
          imports {
              mavenBom "io.grpc:grpc-bom:1.43.0"
          }
      }
      //==============protobuf配置================
      
      sourceSets {
          main {
              proto {
                  srcDir 'src/main/proto'
              }
      
          }
          test {
              proto {
                  srcDir 'src/test/proto'
              }
          }
      
      }
      
      protobuf {
          protoc {
              //从仓库下载
              artifact = 'com.google.protobuf:protoc:3.19.1'
              //生成代码的目录
              generatedFilesBaseDir = "$projectDir/src/"
              plugins {
                  grpc {
                      artifact = "io.grpc:protoc-gen-grpc-java:1.43.0"
                  }
              }
      
              generateProtoTasks {
                  //protobuf源码输出目录
                  all().each { task ->
                      task.builtins {
                          java {
                              outputSubDir = 'grpc'
                          }
                      }
                  }
                  //grpc源码输出目录
                  all()*.plugins {
                      grpc {
                          outputSubDir = 'grpc'
                      }
                  }
      
              }
          }
      }
      
      //==============protobuf配置================
      
      
      //在build之前执行proto代码生成
      build.dependsOn(":grpc-demo:grpc-api:generateProto")
      
      clean {
          delete protobuf.generatedFilesBaseDir + "/main/grpc"
      }
      
      dependencies {
          compile 'com.google.protobuf:protobuf-java-util:3.19.1'
          compile 'com.google.protobuf:protobuf-java:3.19.1'
          compile 'io.grpc:grpc-stub'
          compile 'io.grpc:grpc-protobuf'
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
    2. 使用Protocol Buffers来定义服务接口,新建一个HelloService.proto文件,放在grpc-demo/grpc-api/src/main/proto/HelloService.proto目录下

      syntax="proto3";
      option java_multiple_files = true;
      package cn.jannal.grpc.facade.dto;
      
      message HelloRequest {
        string firstName = 1;
        string lastName = 2;
      }
      
      message HelloResponse {
        string greeting = 1;
      }
      
      service HelloService {
        rpc hello(HelloRequest) returns (HelloResponse);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

    开发服务端

    1. 新建grpc-demo:grpc-provider模块

      apply plugin: "io.spring.dependency-management"
      dependencyManagement {
          imports {
              mavenBom "io.grpc:grpc-bom:1.43.0"
          }
      }
      dependencies {
          compile project(":grpc-demo:grpc-api")
          compile 'io.grpc:grpc-netty-shaded'
          compile 'io.grpc:grpc-protobuf'
          compile 'io.grpc:grpc-stub'
          compile "io.grpc:grpc-services"   // reflection
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    2. 新建GrpcProvider

      @Slf4j
      public class GrpcProvider {
          public static void main(String[] args) throws IOException {
              int port = 8081;
              ServerBuilder serverBuilder = ServerBuilder
                      .forPort(port)
                      .addService(new HelloServiceImpl());
      
              Server server = serverBuilder.build();
              Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                  if (server != null) {
                      server.shutdown();
                  }
                  log.info("Server Shutdown!");
              }));
              serverBuilder.intercept(TransmitStatusRuntimeExceptionInterceptor.instance());
              server.start();
              log.info("Server start port {} !", port);
              startDaemonAwaitThread(server);
      
      
          }
      
          private static void startDaemonAwaitThread(Server server) {
              Thread awaitThread = new Thread(() -> {
                  try {
                      server.awaitTermination();
                  } catch (InterruptedException ignore) {
      
                  }
              });
              awaitThread.setDaemon(false);
              awaitThread.start();
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36

    开发消费端

    1. 新建grpc-demo:grpc-consumer模块

      apply plugin: "io.spring.dependency-management"
      dependencyManagement {
          imports {
              mavenBom "io.grpc:grpc-bom:1.43.0"
          }
      }
      dependencies {
          compile project(":grpc-demo:grpc-api")
          compile 'io.grpc:grpc-netty-shaded'
          compile 'io.grpc:grpc-protobuf'
          compile 'io.grpc:grpc-stub'
          compile "io.grpc:grpc-services"   // reflection
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    2. 同步调用

      @Slf4j
      public class GrpcConsumer {
      
          public static final String IP = "127.0.0.1";
          public static final int PORT = 8081;
      
          public static void doFuture() throws Exception {
              ManagedChannel channel = ManagedChannelBuilder.forAddress(IP, PORT)
                      .usePlaintext()// 启用明文
                      .build();
              HelloServiceGrpc.HelloServiceFutureStub stub = HelloServiceGrpc.newFutureStub(channel);
              ListenableFuture<HelloResponse> future = stub.hello(HelloRequest.newBuilder()
                      .setFirstName("Jannal")
                      .setLastName("Jan")
                      .build());
              HelloResponse helloResponse = future.get();
              log.info("服务端响应:{}", helloResponse);
          }
        
          public static void main(String[] args) throws Exception {
              doSync();
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    3. 异步调用

      public static void doASyncCallback() {
          ManagedChannel channel = ManagedChannelBuilder.forAddress(IP, PORT)
                  .usePlaintext()
                  .build();
          HelloServiceGrpc.HelloServiceStub stub = HelloServiceGrpc.newStub(channel);
          stub.hello(HelloRequest.newBuilder()
                  .setFirstName("Jannal")
                  .setLastName("Jan")
                  .build(), new StreamObserver<HelloResponse>() {
      
              @Override
              public void onNext(HelloResponse helloResponse) {
                  log.info("服务端响应:{}", helloResponse);
                  try {
                      sleep(10);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
      
              @Override
              public void onError(Throwable t) {
      
              }
      
              @Override
              public void onCompleted() {
      
              }
          });
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
    4. Future方式(可异步转同步)

      public static void doFuture() throws Exception {
          ManagedChannel channel = ManagedChannelBuilder.forAddress(IP, PORT)
                  .usePlaintext()// 启用明文
                  .build();
          HelloServiceGrpc.HelloServiceFutureStub stub = HelloServiceGrpc.newFutureStub(channel);
          ListenableFuture<HelloResponse> future = stub.hello(HelloRequest.newBuilder()
                  .setFirstName("Jannal")
                  .setLastName("Jan")
                  .build());
          HelloResponse helloResponse = future.get();
          log.info("服务端响应:{}", helloResponse);
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    gRPC消息流

    1. 一元RPC模式:一元RPC模式也被称为简单RPC模式。在该模式中,当客户端调用服务器端的远程方法时,客户端发送请求至服务器端并获得一个响应,与响应一起发送的还有状态细节以及trailer元数据,随后客户端关闭连接
    2. 服务端流:在服务器端流RPC模式中,服务器端在接收到客户端的请求消息后,会发回一个响应的序列。这种多个响应所组成的序列也被称为“流”。在将所有的服务器端响应发送完毕之后,服务器端会以trailer元数据的形式将其状态发送给客户端,从而标记流的结束,最后客户端关闭连接。
    3. 客户端流:在客户端流RPC模式中,客户端会发送多个请求给服务器端,而不再是单个请求。服务器端则会发送一个响应给客户端。但是,服务器端不一定要等到从客户端接收到所有消息后才发送响应。
    4. 双向流:在双向流RPC模式中,客户端以消息流的形式发送请求到服务器端,服务器端也以消息流的形式进行响应。调用必须由客户端发起,但在此之后,通信完全基于gRPC客户端和服务器端的应用程序逻辑。
  • 相关阅读:
    Flutter中同步与异步
    maven简单配置
    MySQL入门第三天——数据表的约束
    java毕业设计儿童教育系统Mybatis+系统+数据库+调试部署
    【笔试强训选择题】Day41.习题(错题)解析
    压缩包系列
    龙蜥及其理事分获“2022 OSCAR 尖峰开源社区及项目、尖峰开源人物”奖项
    高性能MySQL实战第02讲:深入理解事务与锁机制(上)
    openmp 通用核心 学习 1
    webpack 笔记
  • 原文地址:https://blog.csdn.net/usagoole/article/details/126247964