gRPC框架

gRPC框架

gRPC简介

RPC

RPC 全称远程过程调用(Remote Procedure Call),是一种像本地调用函数的一种平台无关性的接口调用的实现方案。

简单来说就是可以调用另外一个服务器上的方法.

gRPC

gRPC 架构为 CS , protocol buffer 作为客户端和服务端的 Interface Definition Language (IDL) 来描述服务及方法的请求参数和响应结构及消息数据序列化.它支持跨平台和多语言的特性,用 go 写的服务 API,可以通过其他语言调用.

gRPC 核心思想和其他 RPC 架构一样,围绕服务定义,包含有请求参数和响应值的方法,服务端实现服务接口,客户端使用存根进行调用。

Protocol Buffers

定义

Protocol Buffers 是一种平台无关,语言无关的可扩展的用于序列化数据类似于 XML 的接口定义语言(Interface Definition Language)。

语法(proto3)

使用 message 类型进行结构化数据的定义
syntax = "proto3";

message SerachRequest{
    string query = 1;
    int32 page_number = 2;
    int32 result_per_page =3;
}

说明

第一行指定了 Protocol Buffers 的语法,现在有 proto2proto3 ,第一行必须表明语法。每个字段都是一个键值对,并且还要标明每个字段的唯一数值。字段的数值在 1-15 编码占一个字节,16-2047 占2个字节。可以指定字段的规则,单个(默认)或者多个(repeated)。

文件的注释风格

使用的 c/c++ 的 // 或 /* .. */,前者为单行注释,后者为多行注释。

Protocol Buffers 编译成 Go 语言类型对应表
.proto Type Notes Go Type
double float64
float float32
int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32
int64 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. int64
uint32 Uses variable-length encoding. uint32
uint64 Uses variable-length encoding. uint64
sint32 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32
sint64 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64
fixed32 Always four bytes. More efficient than uint32 if values are often greater than 228. uint32
fixed64 Always eight bytes. More efficient than uint64 if values are often greater than 256. uint64
sfixed32 Always four bytes. int32
sfixed64 Always eight bytes. int64
bool bool
string A string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 232. string
bytes May contain any arbitrary sequence of bytes no longer than 232. []byte
默认值

如果在编码时没有指定其字段的值则会使用默认值,string 默认值为空字符串, bytes 默认值为空 bytes, bools 默认值为 false,数值类型的默认值为 0。message 类型为对应语言的默认值。

注意: 对于标量 message 字段,一旦被解析就无法显示设置默认值。

保留字段
enum Foo {
  reserved 2, 15, 9 to 11, 40 to max;
  reserved "FOO", "BAR";
}

保留字段主要是考虑到兼容性,避免删除字段或注释字段。如一方使用了删除或注释字段而另一方没有使用时,而出现的意外情况。使用保留字段,编译过程会提示错误。

使用其他 message 类型
message SearchResponse {
    repeated Result results = 1;
}

message Result {
    string url =1;
    string titile = 2;
    repeated string snippets =3;
}
map 类型
map<string, Project> projects = 3;
RPC service 类型
service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse);
}    

生成代码

生成对应语言的代码参考官网

安装 protoc 编译器[ 手动下载解压至安装目录并加入到环境变量 ]

地址:https://github.com/protocolbuffers/protobuf/releases

安装 go 插件

go install google.golang.org/protobuf/cmd/protoc-gen-go

注意:官网推荐使用上面的插件,对于 go-zero 项目生成 grpc 代码是老版本 v1.4.x 。

编译 go 文件

protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto

protoc --proto_path=$SRC_DIR --go_out=$DST_DIR --go_opt=paths=source_relative $SRC_DIR/addressbook.proto

说明:

- I--proto_path 都表示 .proto 文件的所在位置,如果不指定默认为当前位置。

--go_out 表示生成的 Go 代码的输出位置。

$SRC_DIR/addressbook.proto 表示要编译的 .proto 文件。

--go_opt 表示生成 Go 代码的可选项。详情

使用第二种方式生成代码的参数说明:

一个良好的符合 Go 风格中的 .proto 文件中理应加上 option go_package = "[go module name]/[generate code output path]..." 格式行即完整的生成文件输出位置。

--proto_path-I 与输入的 .proto 文件相关,--go_opt=paths=source_relavtive 是相对于 --go_out 的路径。

按照以上示例会在 $DST_DIR 目录下生成 addressbook.pb.go 文件。

踩坑(protoc 版本为 v3.14.0)

  • 当 option 不存在 .proto 文件中时,生成文件的包名是安装文件的名称进行生成的,具体文件名参考生成文件。当存在 option go_pakcage=baroption go_pakcage=github.com/far/bar 包名为 bar 。
  • option 选项可以指定文件生成对应语言文件的文件位置和包名,现在规范把 options 加上以指定位置和包名。option go_package = "路径;包名"; 这是其他语言的风格,还是按照 go 的风格进行书写如:option go_package=github.com/example/hello
  • 执行protoc --proto_path=protos/service --go_out=pb protos/service/test.service.v1.proto 若在 test.service.v1.proto 文件中存在 option go_package=example.com/foo/bar 代码,则会在 pb 目录下自动生成 example.com/foo/bar/test.service.v1.pb.go。若 --go_out 所在的 pb 目录不存在, 不会自动生成。
  • 执行 protoc --proto_path=protos/service --go_out=pb protos/service/test.service.v1.proto 若在 .proto 文件中存在 option go_package=bar 选项时或不存在该选项时,会相对于 --proto_path 所指目录生成文件。该命令会在 pb 目录下生成 test.service.v1.pb.go 文件,若 --proto_path=protos ,则生成的内容会改为 service/test.service.v1.pb.go
  • --go_opt=paths=source_relative 表示相对于 --proto_path-I 路径生成目录结构或代码。如执行 protoc --proto_path=. --go_out=pb --go_opt=paths=source_relative protos/service/test.service.v1.proto命令时,会在 pb 目录下自动生成 protos/service/test.service.v1.pb.go ;若改成 protoc --proto_path=protos/service --go_out=pb --go_opt=paths=source_relative protos/service/test.service.v1.proto 命令,则在 pb 目录下自会生成 test.service.v1.proto 文件。

gRPC 使用

API文档

获取 gRPC 包

go get google.golang.org/grpc

安装生成 gRPC 代码插件

go get google.golang.org/grpc/cmd/protoc-gen-go-grpc

生成 gRPC 代码

protoc -I $SRC --go_out=plugins=grpc:$DST [filepath]

注意:上面能够生成 grpc 代码,是因为 protoc-gen-go 插件中内置了生成 gRPC 代码的插件(2021.1.7补充)

protoc --go_out=. --go_opt=paths=source_relative \ --go-grpc_out=. --go-grpc_opt=paths=source_relative \ helloworld/helloworld.proto

推荐使用下面的命令生成代码。

两种命令生成方式解释说明

grpc官网

gRPC插件readme

说明

通过 .proto 文件定义服务,gRPC 允许四种服务方法。

简单 RPC,就像普通函数调用,客户端发送存根到服务器,等待服务器响应。
service RouteGuide{
    // a simple RPC method
    rpc GetFeature (Point) returns (Feature){}
}
服务器端流式 RPC,客户端发送请求到服务器,获取服务器数据流直到没有数据返回。
service RouteGuide{
    // a server-side streaming RPC method
    rpc ListFeature (Rectangle) returns (stream Feature){}
}
客户端流式 RPC,客户端使用提供的流,写消息序列到服务器。一旦完成消息队列的写入,就等到服务器将它们全部读取然后响应。
service RouteGuide{
     // a client-side streaming RPC method
    rpc RecordRoute(stream Point) returns (RouteSummary) {}
}
双向流式 RPC,客户端和服务器都是独立的利用读写流,写一串消息到对方。所以它们可以按照自己的顺序进行读写。
service RouteGuide{
     // a bidirectional streaming RPC
    rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}

gRPC 服务的生命周期为:

  1. 客户端调用 RPC 方法,服务器接收到带有客户端元信息,方法名和超时时间(存在的话)的 RPC 被执行。
  2. 服务器立马返回服务器的初始元数据(在任何响应之前发送)或等待接收客户端的请求消息,谁先发生特定与应用程序。
  3. 服务器接收到客户端请求消息后,填充响应消息结构和对应的状态信息(状态码和可选消息)返回。
  4. 完成调用

对于客户端流、服务器流或双向流声明周期大体相同,区别在于:

  1. 服务器流:服务端等待接收到客户端消息后,发送完所有响应数据,完成调用;客户端等待服务端响应后完成调用。
  2. 客户端流:服务端通常(不是必须)等待接收到所有消息后,响应消息,完成调用;客户端发送完所有的消息后完成调用。
  3. 双向流:它们是相互独立的对象,什么时候完成取决于自身。

代码示例

示例代码仓库

说明

  • gRPC 是CS结构,对于同步和异步问题在大部分语言中有两种方式实现,具体详情查看相关语言的具体实现。
  • gRPC 在 Go 中的实现是阻塞同步模式。
  • gRPC 使用 Protocol Buffers 作为接口定义语言。
  • gRPC 服务调用可以指定超时和元数据。元数据为一组键值对,键为字符串,值为字符串数组。在 Go 中指定超时传递是用过 context 来指定的,其中它的传递过程是可以跨进程的,这是因为它利用了它在 HTTP2 协议头中加入了 grpc-timeout ,通过在服务器端解析协议中的超时标记达到效果。

身份认证

错误处理

官网说明

关于

版本日志

  • 第一版:2020 年 05 月 16 日
  • 第二版:2021 年 01 月 08 日
  • 第三版:2021 年 02 月 23 日(增加 protoc 工具对生成 grpc 代码的各个参数说明)

credentials 证书

authentication 身份认证、认证方式

authorization 授权


 上一篇
实用工具 实用工具
实用工具自己在平时的开发过程中,发现的一些比较好用的一些网站和实用工具,仅用于学习使用。 域名服务商:NameSilo 服务器:HostDare CDN加速:Cloudflare 邮箱:Gmail
2020-05-20
下一篇 
EveryDay English EveryDay English
Everyday EnglishYear: 2020 Month: 05Day: 11 单词 翻译 fetch 取 integrate 整合 schema 概要,架构,结构 retrieve 取回,检索 origi
2020-05-13
  目录