最近GRPC很火,感覺整RPC不用GRPC都快跟不上時髦了,
gRPC設計
gRPC是一種與語言無關的高性能遠程程序呼叫 (RPC) 框架,剛好需要使用一個的RPC應用系統,自然而然就盯上了它,但是它真能夠解決所有問題嗎?不見得,先看看他的優點:
gRPC的主要優點:
- 現代高性能輕量級 RPC 框架,
- 協定優先 API 開發,默認使用協議緩沖區,允許與語言無關的實作,
- 可用于多種語言的工具,以生成強型別服務器和客戶端,
- 支持客戶端、服務器和雙向流式處理呼叫,
- 使用
Protobuf二進制序列化減少對網路的使用,
對應的適用場景:
- 微服務:gRPC 設計用于低延遲和高吞吐量通信, gRPC 對于效率至關重要的輕量級微服務非常有用,
- 點對點實時通信:gRPC 對雙向流式傳輸提供出色的支持, gRPC 服務可以實時推送訊息而無需輪詢,
- 多語言環境:gRPC 工具支持所有常用的開發語言,因此,gRPC 是多語言環境的理想選擇,
- 網路受限環境:gRPC 訊息使用 Protobuf(一種輕量級訊息格式)進行序列化, gRPC 訊息始終小于等效的 JSON 訊息,
gRPC還是有缺點的:
- 瀏覽器支持受限:絕大數瀏覽器不支持
HTTP/2 - 非人工可讀取:proto檔案規定的格式在通訊中會序列化成二進制資料,人工決議較為困難,
不適用的場景與替代:
- 瀏覽器可訪問的API:gRPC 在瀏覽器中未受到完全支持,
gRPC-Web可以提供瀏覽器支持,但它具有局限性并引入了服務器代理, - 廣播實時通信:gRPC 支持通過流式傳輸進行實時通信,但不存在將訊息廣播到注冊連接的概念, 例如,在聊天室方案中,應將新的聊天訊息發送到聊天室中的所有客戶端,這要求每個 gRPC 呼叫將新的聊天訊息單獨流式傳輸到客戶端, SignalR 是適用于此方案的框架, SignalR 具有持久性連接的概念,并內置對廣播訊息的支持,
- 行程間通信:行程必須托管 HTTP/2 服務器才能接受傳入的 gRPC 呼叫, 對于 Windows,行程間通信管道是一種快速、輕便的通信方法,
目標分析
我需要有一個能夠實作遠程呼叫的好辦法,系統支持Windows就好,最好性能高一些(資料量大),程式小一點,但是我也不想直接處理二進制資料流(最好能有封裝的框架),
考慮行程通信常用的:
- 信號/信號量:簡單,能夠承載的訊息內容較少,
- 訊息佇列:支持訊息,功能較為強大,
- 共享記憶體:性能最強,但只限于單機,
- 管道:性能較強,但是只支持stream,
- Socket:最靈活,但是需要有網卡,
首先排除信號/信號量,處理的資訊量太小了;然后共享記憶體也排除,只能單機不符合我的要求;剩下的三個似乎都可以滿足要求,可以在這個基礎上建立RPC,而gRPC就是建立在socket(HTTP/2)上的,就像上面講的,要自己集成一個HTTP/2服務器(比如Kestrel)才行,不夠輕量化;剩下的兩個Windows都有內建支持,可以考慮一下,
本著拿來主義的思想,我在github上找到一個grpc-dotnet-namedpipes,支持在命名管道上實作gRPC,相當于在stream上封裝了一層,不用直接處理二進制資料流了,
用作者自己的話來說,這么做相較于普通的gRPC有幾個優點:
- 更優秀的訪問控制;
- 純.NET庫,不需要帶ASP.NET Core或者超過3MB的非托管庫依賴;
- 啟動時間更快
- 2-3倍的資料吞吐量
- 沒有防火墻警告
- 不需要網卡
實作
建立一個proto
- 創建一個.NET Library
- 添加一個proto檔案,可以直接使用微軟的簡單例子
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
- 添加nuget包:
Google.Protobuf,Grpc.Core,Grpc.Tools - 單擊proto檔案,在屬性對話框,選擇生成操作為Protobuf Compiler
建立Client
新建一個Console程式,添加上面的專案參考,輸入以下代碼:
var server = new NamedPipeServer("MY_PIPE_NAME");
Greeter.BindService(server.ServiceBinder, new GreeterService());
server.Start();
添加GrpcDotNetNamedPipes的nuget依賴:
Install-Package GrpcDotNetNamedPipes
建立Server
再新建一個Console程式,添加上面的專案參考,也添加那個nuget依賴和一些別的依賴,輸入以下代碼:
var channel = new NamedPipeChannel(".", "MY_PIPE_NAME");
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(
new HelloRequest { Name = "World" });
Console.WriteLine(response.Message);
然后運行就能看見熟悉的Hello World了,用起來和gRPC的標準實作沒太大區別,
總結
完整代碼見gRPC_Demo,
這種方式也有它的局限性,首先是Windows的命名管道與Linux上面的實作是不同的,所以并不能實作直接跨平臺通訊;然后就是這個對于其他語言的開發的gRPC也不是完全兼容的,需要其他語言開發的程式也做命名管道的適配才行,換言之,它不是通用標準,所以,對于一般的gRPC應用,還是更推薦使用標準實作,
參考
- .NET Core 上的 gRPC 的簡介
- 比較 gRPC 服務和 HTTP API
- 關于IPC性能的提問
- Linux上各種IPC性能比較
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/4858.html
標籤:C#
上一篇:C#資料型別及其轉換詳解
下一篇:C#設計模式
