淺談.NET 6 中 gRPC 的最新功能

微軟技術棧 發表於 2022-01-15
.Net

gRPC 是一個現代的、跨平臺的、高效能的 RPC 框架。gRPC 是構建在 ASP.NET Core 之上,也是我們推薦的使用 .NET 構建 RPC 服務的方法。

.NET 6 進一步提高了 gRPC 已經非常出色的效能,並新增了一系列新功能,使 gRPC 在現代雲原生應用程式中比以往任何時候都更好。在這篇文章中,我將描述這些新功能以及我們如何通過第一個支援端到端 HTTP/3 的 gRPC 實現引領行業。

gPRC 客戶端負載均衡

客戶端負載平衡是一項允許 gRPC 客戶端在可用伺服器之間優化分配負載的功能。客戶端負載平衡可以消除對負載平衡代理的需要。這有幾個好處:

  • 改進的效能。無代理意味著消除額外的網路躍點並減少延遲,因為 RPC 直接傳送到 gRPC 伺服器。
  • 有效利用伺服器資源。負載平衡代理必須解析然後重新傳送通過它傳送的每個 HTTP 請求。刪除代理可以節省 CPU 和記憶體資源。
  • 更簡單的應用程式架構。必須正確設定和配置代理伺服器。沒有代理伺服器意味著更少的活動部件!

客戶端負載均衡是在建立通道時配置的。使用負載均衡時要考慮的兩個元件:

  • 解析器,解析通道的地址。解析器支援從外部源獲取地址。這也稱為服務發現。
  • 負載均衡器,它建立連線並選擇 gRPC 呼叫將使用的地址。

以下程式碼示例將通道配置為使用具有迴圈負載平衡的 DNS 服務發現:

var channel = GrpcChannel.ForAddress(

"dns:///my-example-host",
newGrpcChannelOptions
{
    Credentials = ChannelCredentials.Insecure,
    ServiceConfig = newServiceConfig { LoadBalancingConfigs = { newRoundRobinConfig() } }
});

var client = newGreet.GreeterClient(channel);
var response = await client.SayHelloAsync(newHelloRequest { Name = "world" });

更多資訊,請參閱 gPRC 客戶端負載平衡

帶有重試的瞬間故障處理

gRPC 呼叫可能會被瞬時故障中斷。瞬態故障包括:

  • 網路連線暫時中斷。
  • 服務暫時不可用。
  • 由於伺服器負載超時。

當 gRPC 呼叫被中斷時,客戶端會丟擲一個包含錯誤詳細資訊的 RpcException。客戶端應用程式必須捕獲異常並選擇如何處理錯誤。
var client =newGreeter.GreeterClient(channel);
try
{

var response =await client.SayHelloAsync(
    newHelloRequest{Name=".NET"});

Console.WriteLine("From server: "+ response.Message);

}
catch(RpcException ex)
{

// Write logic to inspect the error and retry
// if the error is from a transient fault.

}

在整個應用程式中複製重試邏輯是冗長且容易出錯的。幸運的是,.NET gRPC 客戶端現在內建了對自動重試的支援。重試在通道上集中配置,並且有許多選項可用於使用 RetryPolicy 自定義重試行為。

var defaultMethodConfig =newMethodConfig
{

Names={MethodName.Default},
RetryPolicy=newRetryPolicy
{
    MaxAttempts=5,
    InitialBackoff=TimeSpan.FromSeconds(1),
    MaxBackoff=TimeSpan.FromSeconds(5),
    BackoffMultiplier=1.5,
    RetryableStatusCodes={StatusCode.Unavailable}
}

};

// Clients created with this channel will automatically retry failed calls.
var channel =GrpcChannel.ForAddress("https://localhost:5001",newGrpcChannelOptions
{

ServiceConfig=newServiceConfig{MethodConfigs={ defaultMethodConfig }}

});

有關更多資訊,請參閱使用 gRPC 重試進行瞬態故障處理

Protobuf 效能

關於.NET 的 gRPC 使用 Google.Protobuf 包作為訊息的預設序列化程式。Protobuf 是一種高效的二進位制序列化格式。Google.Protobuf 旨在提高效能,使用程式碼生成而不是反射來序列化 .NET 物件。在 .NET 5 中,我們與 Protobuf 團隊合作,為序列化程式新增了對現代記憶體 API(例如 Span<T>、ReadOnlySequence<T>和IBufferWriter<T>)的支援。.NET 6 中的改進優化了一個已經很快的序列化程式。
protocolbuffers/protobuf#8147新增了向量化字串序列化。SIMD 指令允許並行處理多個字元,從而在序列化某些字串值時顯著提高效能。

privatestring _value =newstring(' ',10080);
privatebyte[] _outputBuffer =newbyte[10080];
[Benchmark]
publicvoidWriteString()
{

var span =newSpan<byte>(_outputBuffer);
WriteContext.Initialize(ref span,outWriteContext ctx);
ctx.WriteString(_value);
ctx.Flush();

}

image.png

protocolbuffers/protobuf#7645新增了一個用於建立 ByteString 例項的新 API。如果你知道底層資料不會改變,那麼使用 UnsafeByteOperations.UnsafeWrap 來建立一個 ByteString 而不復制底層資料。如果應用程式處理大位元組有效負載並且您想降低垃圾收集頻率,這將非常有用。

gPRC 下載速度

gRPC 使用者報告有時下載速度變慢。我們的調查發現,當客戶端和伺服器之間存在延遲時,HTTP/2 流量控制會限制下載。伺服器在客戶端可以耗盡之前填充接收緩衝區視窗,導致伺服器暫停傳送資料。gRPC 訊息以開始/停止突發方式下載。

這已在 dotnet/runtime#54755中修復。HttpClient 現在動態縮放接收緩衝區視窗。建立HTTP/2 連線後,客戶端將向伺服器傳送 ping 以測量延遲。如果存在高延遲,客戶端會自動增加接收緩衝區視窗,從而實現快速、連續的下載。

privateGrpcChannel _channel =GrpcChannel.ForAddress(...);
privateDownloadClient _client =newDownloadClient(_channel);

[Benchmark]
publicTaskGrpcLargeDownload()=>

_client.DownloadLargeMessageAsync(newEmptyMessage());

image.png

HTTP/3 支援

NET 上的 gRPC 現在支援 HTTP/3。gRPC 建立在 .NET 6 中新增到 ASP.NET Core 和 HttpClient 的 HTTP/3 支援之上。有關更多資訊,請參閱.NET 6 中的 HTTP/3支援。
.NET 是第一個支援端到端 HTTP/3 的 gRPC 實現,我們已經為其他平臺提交了 gRFC,以便將來支援 HTTP/3。帶有 HTTP/3 的 gRPC 是開發人員社群高度要求的功能,很高興看到 .NET 在該領域處於領先地位。
image.png

總結

效能是 .NET 和 gRPC 的一個特性,而 .NET 6 比以往任何時候都快。客戶端負載平衡和 HTTP/3 等以效能為導向的新功能意味著更低的延遲、更高的吞吐量和更少的伺服器。這是一個節省資金、減少能耗和構建更環保的雲原生應用程式的機會。

要試用新功能並開始在 .NET 中使用 gRPC,最好的起點是在 ASP.NET Core 教程中建立 gRPC 客戶端和伺服器。

我們期待聽到有關使用 gRPC 和 .NET 構建的應用程式以及您在 dotnetgrpc 儲存庫中的貢獻!

.NET 上的 gRPC參考文件