首页 > 其他分享 >gRPC

gRPC

时间:2023-06-28 15:58:47浏览次数:48  
标签:proto gRPC boot server grpc message eureka

一、protobuf

gRPC传输用这个挺好的,跨语言调用

  • 足够简单
  • 序列化后体积小
  • 解析速度比XML块
  • 多语言支持
  • 兼容性好

proto3

这里就先不提proto2了
文件后缀名是 .proto

1.开始部分

syntax = "proto3"; // compile is proto3

// 生成的文件是处在哪个目录哪个包中,.代表在当前目录生成,service代表文件生成的包名是service
option java_package = ".;service";

2.Message

可以理解为需要传输的数据格式的定义,类似于Java中的类class。使用 protobuf 编译器将 proto 编译成 java 代码后,每个 message 都会生成一个名字与之对应的类。

字段规则:

  • optional:可选字段,默认为可选字段
  • repeate:可重复字段 => 数组

消息号:
每个字段必须有一个唯一的标识号,不能重复,范围[2,2&29-1]

message SearchRequest {
	string query = 1;// 每个字段必须有一个唯一的标识号,不能重复,范围:[2,2^29-1]
	int32 page_number = 2;
	int32 result_per_page = 3;
}

1.Type

double, float, int32, int64, uint32, uint64, sint32, sint64,(s* is more effcient in negative number)
fixed32, fixed64, sfixed32, sfixed64, bool, string, bytes.

repeated //by index
Timestamp
Duration
Struct
ListValue

默认值

string ""
bytes ""
bool false
numeric 0
enums 0
message fields are language-dependent.

image.png

2.enum

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAEGS = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  Corpus corpus = 4;
}
/////////////////////////////////////
message MyMessage1 {
  enum EnumAllowingAlias {
    option Allow_alias = true; // same variable in different enums, need this options
    UNKNOWN = 0;
    STARTED = 1;
    RUNNING = 1;
  }
}
message MyMessage2 {
  enum EnumNotAllowingAlias {
    UNKNOWN = 0;
    STARTED = 1;
    // RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside.
  }
}

3.using other message

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

4.Importing Definitions

JAVA is not suitable

5.Nested Types

as deeply as U like

// 1 *************************
// staight Nested another message
message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snipeets = 3;
}

// 2 ***************************
// nest partial message
message SomeOtherMessage {
  SearchResponse.Result result = 1;
}

6.any

7.one of

have many fields but use ao most one field once.
a oneof cannot be repeated.

message SampleMessage{
  oneof test_oneof {
    string name = 4;
    SubMessage submessage = 9;
  }
}

SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
message.mutable_sub_message(); // Will clear name filed;
CHECK(!message.has_name());

8.Maps

map<string, Project> projects = 3;

9.Define Services

service SearchService{
  rpc Search(SearchRequest) return (SearchResponse);
  rpc Search1(SearchRequest) return (stream SearchResponse); // 服务端流式 gRPC 响应
  rpc Search2(stream SearchRequest) return (SearchResponse); // 客户端流式 gRPc 通信
}

10.Generating Classes

protoc --proto_path=IMPORT_PATH --cpp_out --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto
# *_out point the DST_DIR of the output
# proto_path points the import_PATH?
# path/to/file.proto is the file be compiling.

protoc -I=$SRC_DIR --cpp_out=$DST_DIR xxx.proto

  • $SRC_DIR: proto所在的源目录
  • --cpp_out:生成 cpp 代码
  • $DST_DIR:生成代码的目标目录
  • xxx.proto:要针对哪个 proto 文件生成接口,例如 tutorial.person.proto

编译完成后,将生成 2 个文件,tutorial.pb.htutorial.pb.c,pb 是 protobuf 的缩写。
此外,protocol buffer 编译器为.proto文件中定义的消息的每个字段生成一套存取器方法:
对于 message Person 中的 required int32 id = 2,编译器将生成下列存取器方法:
bool has_id() const: 用于判断字段id是否存在。如果字段被设置,返回true。
**int32 id() const: **返回字段id的当前值,如果字段没有被设置,返回缺省值。
void set_id(int32 value) : 设置字段id的值。调用此方法后,has_id() 将返回true以及id() 将返回value。
void clear_id():清除字段的值。调用此方法后,has_id()将返回false 以及id()将返回缺省值。
当然,对于其他类型的字段,编译器也会生成不同的存取方法,这里就不一一列举了。

二、rpc 通信模式

image.png

stub-存根,客户端使用
ImplBase-骨架类,服务端使用

1.一元 RPC 通信模式

image.png
使用newBlockingStub方法,同步,

2.服务端流式 RPC 通信模式

image.png
使用newBlockingStub,支持服务器端推流

3.客户端流式 RPC 通信模式

image.png
使用 newStub,异步通信

4.双向流式 RPC 通信模式

跟 3 差不多,使用 newStub,异步通信

三、gRPC 集成到 springboot 与 Eureka

1.集成 springboot

使用下面的 starter ,结合注解与配置文件使用
pom 文件(c 端与 s 端只是使用的具体 starter 不同,s 为grpc-server-spring-boot-starter,c 为grpc-client-spring-boot-starter):

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>spring-boot-demo</artifactId>
        <groupId>com.zhangyu</groupId>
        <version>0.0.1</version>
    </parent>
    <artifactId>grpc-server-spriongboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>grpc-server-spriongboot</name>
    <description>grpc-server-spriongboot</description>
    <properties>
        <java.version>11</java.version>
        <protoc.version>3.21.5</protoc.version>
        <protobuf.version>1.51.0</protobuf.version>
        <protobuf-maven-plugin.version>0.6.1</protobuf-maven-plugin.version>
    </properties>
    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- grpc-server -->
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-server-spring-boot-starter</artifactId>
            <version>2.14.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <extensions>
            <!-- 为了识别不同的操作系统,这样插件可以根据不同的平台加载不同protoc编译器文件 -->
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>${protobuf-maven-plugin.version}</version>
                <configuration>
                    <pluginId>grpc-java</pluginId>
                    <!-- proto文件放置的目录 -->
                    <!-- <protoSourceRoot>${basedir}/src/main/proto</protoSourceRoot> -->
                    <!-- 生成文件的目录, 可以让其在源码目录生成 -->
                    <!-- <outputDirectory>${project.basedir}/src/main/java</outputDirectory>-->
                    <!-- 生成文件前是否把目标目录清空,这个最好设置为false,以免误删项目文件 -->
                    <!-- <clearOutputDirectory>false</clearOutputDirectory>-->

                    <!-- 寻找本机 protoc 执行命令,需配置环境变量 -->
                    <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
                    </protocArtifact>
                    <!-- 生成 grpc 的通信类 -->
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${protobuf.version}:exe:${os.detected.classifier}
                    </pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <!-- 生成消息代码 -->
                            <goal>compile</goal>
                            <!-- 生成 grpc 的通信文件 -->
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

application.yml:

  • s 端
server:
  port: 8080
grpc:
  server:
    port: 9090
  • c 端
server:
  port: 8081
grpc:
  client:
    # 自定义名称,结合@GrpcClient("grpc-server")使用,得到存根bean
    grpc-server:
      # static 是使用静态地址
      address: 'static://127.0.0.1:9090'
      # 文本传输
      negotiation-type: plaintext

业务代码层:

  • s 端
@GrpcService // 需要加这个注解
public class NewService extends NewsServiceGrpc.NewsServiceImplBase {
    @Override
    public void list(NewsProto.NewsRequest request, StreamObserver<NewsProto.NewsResponse> responseObserver) {
        String date = request.getDate();
        NewsProto.NewsResponse response = NewsProto.NewsResponse.newBuilder().setTitle("新闻-" + date).build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}
  • c 端
@RestController
@RequestMapping("/grpc")
public class NewsController {
    
    // 指明使用的配置文件的自定义名称,来获取存根类 bean
    @GrpcClient("grpc-server")
    private NewsServiceGrpc.NewsServiceBlockingStub blockingStub;

    @GetMapping("/news/list")
    public String listNews(@RequestParam(value = "date") String date) {

        NewsProto.NewsResponse response = blockingStub.list(NewsProto.NewsRequest.newBuilder().setDate(date).build());

        return response.getTitle();
    }
}

2.接入 Eureka

微服务体系(不过这好像是 cloud 一代目的东西?不是很清楚)
image.png
ps:二代目是这样:
image.png

1.Eureka 服务端

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Eureka 记得声明 colud 的版本-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
server:
	# 服务开在 8761 端口
  port: 8761

eureka:
  server:
    # 是否开启自我保护,默认true
    enable-self-preservation: false
  instance:
    appname: eureka-server
    hostname: localhost
  client:
    service-url:
      # 默认服务注册中心地址
      defaultZone:
        http://localhost:8761/eureka/
    register-with-eureka: false
    fetch-registry: false

具体配置查看Eureka 在 application.yml 里面的配置详解

@SpringBootApplication
// 开启 Eureka 服务器端
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

2.Eureka 客户端 - grpc 服务端

<!-- web -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- grpc-server -->
<!-- client 的话把server 换成 client 就行 -->
<dependency>
  <groupId>net.devh</groupId>
  <artifactId>grpc-server-spring-boot-starter</artifactId>
  <version>2.14.0.RELEASE</version>
</dependency>

<!-- Eureka -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

//---------
<build>
  <extensions>
    <!-- 为了识别不同的操作系统,这样插件可以根据不同的平台加载不同protoc编译器文件 -->
    <extension>
      <groupId>kr.motd.maven</groupId>
      <artifactId>os-maven-plugin</artifactId>
      <version>1.5.0.Final</version>
    </extension>
  </extensions>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
    </plugin>
    <plugin>
      <groupId>org.xolstice.maven.plugins</groupId>
      <artifactId>protobuf-maven-plugin</artifactId>
      <version>${protobuf-maven-plugin.version}</version>
      <configuration>
        <pluginId>grpc-java</pluginId>
        <!-- proto文件放置的目录 -->
        <protoSourceRoot>${basedir}/src/main/proto</protoSourceRoot>
        <!-- 生成文件的目录, 可以让其在源码目录生成 -->
        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
        <!-- 生成文件前是否把目标目录清空,这个最好设置为false,以免误删项目文件 -->
        <clearOutputDirectory>false</clearOutputDirectory>

        <!-- 寻找本机 protoc 执行命令,需配置环境变量 -->
        <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
        </protocArtifact>
        <!-- 生成 grpc 的通信类 -->
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:${protobuf.version}:exe:${os.detected.classifier}
        </pluginArtifact>
      </configuration>
      <executions>
        <execution>
          <goals>
            <!-- 生成消息代码 -->
            <goal>compile</goal>
            <!-- 生成 grpc 的通信文件 -->
            <goal>compile-custom</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

server:
  port: 8080

spring:
  application:
    # 此名字会向 Eureka 注册
    name: spb-server-eureka
eureka:
  client:
    service-url:
      # 具体哪个地址提供了 Eureka 服务
      defaultZone:
        http://localhost:8761/eureka/
grpc:
  server:
    # 采用一个未占用的随机端口号来提供 gRPC 服务
    port: 0
syntax = "proto3";

option java_multiple_files = false;
option java_package = "com.zhangyu.news.proto";
option java_outer_classname = "NewProto";

package news;

service NewService {
  rpc listNews(NewsRequest) returns(NewsResponse){};
}

message NewsRequest {
  string name = 1;
}

message NewsResponse {
  string result = 1;
}
@SpringBootApplication
// 开启 Eureka 客户端类
@EnableEurekaClient
public class SpbServerEurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpbServerEurekaApplication.class, args);
    }
}

// 开启 grpc 注解
@GrpcService
public class NewsService extends NewServiceGrpc.NewServiceImplBase {

    @Override
    public void listNews(NewProto.NewsRequest request, StreamObserver<NewProto.NewsResponse> responseObserver) {
        String name = request.getName();
        responseObserver.onNext(NewProto.NewsResponse.newBuilder().setResult("News name is " + name).build());
        responseObserver.onCompleted();
    }
}

3.Eureka 客户端 - grpc 客户端

<dependency>
  <groupId>net.devh</groupId>
  <artifactId>grpc-client-spring-boot-starter</artifactId>
  <version>2.14.0.RELEASE</version>
</dependency>

把服务端的 gprc 服务端依赖改成对应的客户端依赖就行

server:
  port: 8081

spring:
  application:
    # 会把这个名字注册到 Eureka 注册中心
    name: spb-client-eureka
  eureka:
    client:
    service-url:
      # 具体哪个地址提供了 Eureka 服务
      defaultZone:
        http://localhost:8761/eureka/
grpc:
  client:
    # 自定义名称,且需服务端的 application 名(即注册到 eureka 的服务名)相同,不需要再显式的写明地址端口号
    spb-server-eureka:
      # 声明传输格式
      negotiation-type: plaintext

@SpringBootApplication
// 开启 Eureka 客户端
@EnableEurekaClient
public class SpbClientEurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpbClientEurekaApplication.class, args);
    }
}
@RestController
@RequestMapping("/grpc")
public class NewsController {
    // 需要与配置文件里面自定义名称相关联,来获取相应的存根类
    @GrpcClient("spb-server-eureka")
    private NewServiceGrpc.NewServiceBlockingStub newServiceBlockingStub;

    @GetMapping("/list")
    public void list() {
        NewProto.NewsResponse newsResponse = newServiceBlockingStub.listNews(NewProto.NewsRequest.newBuilder().setName("震惊!现在居然还有人在用 Eureka!").build());

        System.out.println(newsResponse.getResult());
    }
}

标签:proto,gRPC,boot,server,grpc,message,eureka
From: https://www.cnblogs.com/zerozayu/p/gRPC.html

相关文章

  • gRPC学习记录--python
    gRPC学习记录基于:gRPC官方文档中文版v1.0目录gRPC学习记录gRPC是什么?应用在准备:安装安装Git安装gRPCPython使用protocolbuffersProtocolbuffers版本HelloWorfgRPC!定义服务生成gRPC代码写一个服务器服务实现服务端实现写一个客户端连接服务调用RPC试一下!gRPC......
  • gRPC 的 RoadMap 20160325 更新
    gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(ProtocolBuffers)序列化协议开发,且支持众多开发语言。下面我们就从HTTP2、ProtoBuf3、Nginx、gRPC的角度看他们的RoadMAP。HTTP22015年5月HTTP2协议正式版发布:RF......
  • gRPC
    grpc性能高:http2.0为什么比http1.1性能高?http/1.*:一次请求,一个响应,建立一个连接用完关闭,每一个请求都要建立一个连接http1.1pipeling:Pipeling解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,......
  • gRPC入门与实操(.NET篇)
    为什么选择gRPC#历史#长久以来,我们在前后端交互时使用WebApi+JSON方式,后端服务之间调用同样如此(或者更久远之前的WCF+XML方式)。WebApi+JSON是优选的,很重要的一点是它们两者都是平台无关的三方标准,且足够语义化,便于程序员使用,在异构(前后端、多语言后端)交互场景下是不二......
  • 云原生时代崛起的编程语言Go远程调用gRPC实战
    @目录概述定义背景特点四种服务方法实战环境配置proto文件简单RPCToken认证服务器流式RPC客户端流式RPC双向流式RPC概述定义gRPC官网地址https://grpc.io/源码release最新版本v1.55.1gRPC官网文档地址https://grpc.io/docs/gRPC源码地址https://github.com/grpc/grp......
  • GO实现高可用高并发分布式系统:gRPC实现客户端与服务端的一对一通讯
    分布式系统的特点是不同的功能模块会以独立服务器程序的方式运行在不同主机上。当服务A想请求位于另一台机器的服务B完成特定请求时,就必须将要处理的数据提交给B。这个过程就涉及到一系列问题,首先A需要把数据进行序列化然后通过网络连接发送给B,B接收到数据后需要进行反序列化得到数......
  • 转:翻译:REST 和 gRPC 详细比较
    转自:https://www.cnblogs.com/YGYH/p/17471039.html译者注:在微服务架构设计,构建API和服务间通信技术选型时,对REST和gRPC的理解和应用还存在知识盲区,近期看到国外的这篇文章:AdetailedcomparisonofRESTandgRPC,将二者进行了详细对比。周末有时间翻译过来,希望能帮到大家!......
  • .net core 微服务 集成Ocelot 和Nacos 之后使用grpc 如何实现服务与服务之间的调用
    在.NETCore微服务中使用gRPC调用其他服务,你需要完成以下步骤:1.定义服务契约:你需要定义你的服务、方法以及消息类型,以便客户端和服务端协商通信。2.生成代码:你需要使用gRPC工具生成客户端和服务端的代码,这样你就可以在应用程序中使用它们。3.实现服务:你需要实现......
  • Google 开源 RPC 框架 gRPC
    gRPC是Google开源的一款高性能RPC框架,前两天发布了1.0版本。RPC(RemoteProcedureCall)即远程过程调用,通过RPC,客户端的应用程序可以方便地调用另外一台机器上的服务端程序,因而常被应用于分布式系统中。RPC框架通常使用IDL(InterfaceDescriptionLanguage)定义客户......
  • REST 和 gRPC 详细比较(转)
    译文:https://www.cnblogs.com/YGYH/p/17471039.html译者:iEricLee译者注:在微服务架构设计,构建API和服务间通信技术选型时,对REST和gRPC的理解和应用还存在知识盲区,近期看到国外的这篇文章:AdetailedcomparisonofRESTandgRPC,将二者进行了详细对比。周末有时间翻译过来,希......