gRPC简介并使用
一、简介
gRPC来自Goole,它是一个开源的框架;它同时也是Cloud Native Computation的基金会(CNCF)的一部分,就像Docker和Kubernetes一样。
gRPC允许你为RPC(Remote Procedure Call)定义请求和响应,然后gRPC会帮你处理一切剩余的问题。
它速度快,执行效率高,基于HTTP/2构建,低延迟,支持流,与开发语言无关,并且可以很简单的插入身份认证、负载均衡、日志和监控等功能。
gRPC它是对RPC一种非常简洁的实现并且解决了很多RPC的问题。
如何学习gRPC,首先学习Protocol Buffers,简单的说,它可以用来定义消息和服务。然后,你只需要实现服务即可,剩余的gRPC代码将会自动为你生成。.proto这个文件可以适用于十几种开发语言,并且允许你使用同一个框架来支持每秒百万级以上的RPC调用。
开发模式:gRPC使用合约优先的API开发模式,它默认使用Protocol buffers(protobuf)作为接口设计语言,这个.proto文件包括两部分:
1)gRPC服务的定义;
2)服务端和客户端之间传递的消息;
开发环境,首先需要安装Clang:https://releases.llvm.org/download.html
VSCode 中需要安装vscode-proto3和Clang-Format
二、Protocol Buffers
1、标量类型
消息定义:
syntax="proto3"; message Person{ int32 is=1; string name =2; float height=3; float weight=4; bytes avatar=5; string email=6; bool email_verified=7; }
2、字段的数值(Tag)
在Protocol Buffers里面,字段的名称其实没那么重要,但是写C#代码的时候,字段名还是很重要的。对于protobuf来说,这个tag是更重要的,可以使用的最小tag数值是1,最大值是229-1,或者536,870,911。但是你不可以使用19000到19999之间的数,这部分数是保留的。
还有一点需要注意:
从1到15的tag数只占用1个字节的空间,所以它们应该被用在频繁使用的字段上。而从16到2047,则占用两个字节,它们可以用字不频繁使用的字段上。
3、字段规则
protobuf 的字段必须满足以下两个规则之一:
1)单数字段(Singular):大概意思就是指这个字段只能出现0或1次,这也是proto3的默认字段规则;
2)重复字段(Repeated):如果你想做一个list或数组的话,你可以使用重复字段这个概念,这个list可以有任何数量(包括0)的元素,它里面的值的顺序将会得到保留。
repeated string phone_numbers=8;//packed
4、保留字段
reserved 9,10,20 to 100,200 to max; reserved "foo","bar";
5、字段的默认值
当消息被解析的时候,如果编码的消息里不包含特定的一个sinular元素,那么在被解析对象里响应的字段就会被设为默认值。
常用类型的默认值如下:
string:空字符串
bytes:空的byte数组
bool:false
数值型:0
枚举:枚举里定义的第一个枚举值,值必须是0。
repeated:通常是相应开发语言里的空list
还有一个消息类型的字段,它的默认值与开发语言有关。
6、枚举
枚举Enum的tag必须从0开始,它可以起别名,起别名的作用就是允许两个枚举值拥有同一个数值。想要起别名,首先需要设置allow_alias这个option为true.
常量值不能超过32位整形的数值,枚举可以定义在message里面,也可以再外边单独定义以便复用。
7、自定义消息类型
syntax="proto3"; import "date.proto"; message Person{ int32 is=1; string name =2; float height=3; float weight=4; bytes avatar=5; string email=6; bool email_verified=7; repeated string phone_numbers=8;//packed Gender gender=11; Date birthday=12; reserved 9,10,20 to 100,200 to max; reserved "foo","bar"; repeated Address addresses=13; message Address{ string province=1; string city=2; string street=3; } } enum Gender{ option allow_alias=true; NOT_SPECIFIED=0; FEMALE=1; MALE=2; WOMAN=1; MAN=2; }
8、打包
你可以向proto文件添加可选的打包(package)说明符,以避免消息类型间的名称冲突。
package my.project; option csharp_namespace="Test_Namespace";
9、设置Protocol Buffers编译器
protoc编译器主要是用来生成代码的,下载地址:https://github.com/protocolbuffers/protobuf/releases/
下载后解压,添加环境变量:
输入命令行protoc看一下是否正常:
-IPATH 用来指定哪个文件夹下有我们需要的引用;
指定对应语言生成的路径
打开VSCode终端,执行:
生成C#文件:
生成的文件不要随意改动,需要更改就改.proto文件。
三、更新消息类型
随着需求的变更,消息的字段可能会发生一些变化,可能很多程序都在使用这个消息,那么,我们在对源数据进行演进的时候,一定不要引起破坏性的变化,否则其他程序可能就无法正常工作了。
两种变更情景:
向前兼容变更:使用新的.proto文件来写数据--从旧的.proto文件读取数据
向后兼容变更:使用旧的.proto文件来写数据--从新的.proto文件读取数据
四、gRPC的原理
设计步骤:
生命周期:
身份认证:
五、在.Net Core中应用gRPC
新建一个gRPC项目:
结构如下:
先写Proto文件,定义消息:
然后定义Servers:
public class GreeterService : Greeter.GreeterBase { public override Task<HelloReply> SayHello( HelloRequest request, ServerCallContext context) { return Task.FromResult(new HelloReply { Message = "Hello " + request.Name }); } }
配置 gRPC
在 Startup.cs 中 :
- gRPC 通过
AddGrpc
方法启用。 - 每个 gRPC 服务均通过
MapGrpcService
方法添加到路由管道
public void ConfigureServices(IServiceCollection services) { services.AddGrpc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService<GreeterService>(); }); }
现在在.Net客户端调用gRPC服务:
新建一个控制台项目,配置文件修改:
gRPC 客户端是通过通道创建的。 首先使用 GrpcChannel.ForAddress
创建一个通道,然后使用该通道创建 gRPC 客户端:
static async Task Main(string[] args) { var channel = GrpcChannel.ForAddress("https://localhost:5001"); var client = new Greeter.GreeterClient(channel); var reply = await client.SayHelloAsync( new HelloRequest { Name = "GreeterClient" }); Console.WriteLine("Greeting: " + reply.Message); Console.WriteLine("Press any key to exit..."); Console.ReadKey(); }
具体参考:https://docs.microsoft.com/zh-cn/aspnet/core/grpc/client?view=aspnetcore-3.1