一、簡介
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
