聊聊Grpc使用中的坑以及怎麼填
總所周知,隨著雲技術的發展,和業務的複雜度的上升,越來越多的系統開始拆分成獨立的子模組微服務。模組之間免不了相互通訊。但是隨著業務量的增多,傳輸量也隨之增大,偶發性timeout,無響應, 傳輸量過大等問題。
這時候就要對服務進行配置需要進行調優。可以從運維層面,或者程式碼層面,本文主要介紹從程式碼層面
Grpc是一個很好的微服務框架,大部分語言都支援,之前的文章有介紹,可以看一下。
這次主要說一下在Grpc微服務通訊間的一些問題及優化。運維層面我們就不說了,主要是程式碼層面的優化。主要是C#程式碼,其他語言可參考,Grpc框架都大差不差
問題一:
Docker Swarm 模式下 服務閒置一段時間,客戶端第一次連線會提示異常。咱公網是k8s部署,不清楚為什麼k8s不會出現這個問題。
後來,通過查資料,可以大致知道是這麼個流程。首先 kube-proxy 是支援 IPTABLES 和 IPVS 兩種模式的,
使用的是 IPTABLES不會出現問題。具體為啥,沒做深入連線,運維層面,我們就不吹牛逼。各位看官有興趣去查一下,告訴小弟。
Grpc.Core.RpcException: Status(StatusCode=Unavailable, Detail="Connection reset by peer") at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Grpc.Core.Internal.AsyncCall`2.UnaryCall(TRequest msg) at Grpc.Core.DefaultCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request) at Grpc.Core.Interceptors.InterceptingCallInvoker.<BlockingUnaryCall>b__3_0[TRequest,TResponse](TRequest req, ClientInterceptorContext`2 ctx) at Grpc.Core.ClientBase.ClientBaseConfiguration.ClientBaseConfigurationInterceptor.BlockingUnaryCall[TRequest,TResponse](TRequest request, ClientInterceptorContext`2 context, BlockingUnaryCallContinuation`2 continuation)
解決方案:
1、重試機制
.net 可通過polly 實現,當然,這種方式不太好,畢竟不算根本上解決問題。只能算取巧。可以用第二種,從根本上解決喚醒問題
private readonly Polly.Retry.RetryPolicy RetryPolicy = Policy .Handle<RpcException>(t => t.Status.StatusCode == StatusCode.Unavailable) .Retry(1);
2、還可以通過優化Grpc 服務端程式碼,新增如下配置即可
var server = new Server(new List<ChannelOption> { new ChannelOption("grpc.keepalive_time_ms", 800000), // 傳送 keepalive 探測訊息的頻度 new ChannelOption("grpc.keepalive_timeout_ms", 5000), // keepalive 探測應答超時時間 new ChannelOption("grpc.keepalive_permit_without_calls", 1) // 是否允許在沒有任何呼叫時傳送 keepalive }) { Services = { ServiceA }, Ports = { new ServerPort(host, port, ServerCredentials.Insecure) }, };
問題二:
Grpc傳輸量,預設是4M,如果服務之間呼叫,傳輸資料量超過最大值,會提示 , Received message larger than max (xxxxxx vs. 4194304
解決方案:
1、我們通過程式碼配置,調大這個限制。以提高服務間吞吐量。
當然,不建議太大,太大了對服務資源也是一種消耗。可以通過第二種方式進行優化
var channelOptions = new List<ChannelOption>();
// add max message length option 設最大接收數量 channelOptions.Add(new ChannelOption(ChannelOptions.MaxReceiveMessageLength, (4 * 1024 * 1024) * 7))
2、通過Grpc流式呼叫
Grpc 是基於 HTTP/2 實現的,HTTP/2 具有流的概念,流是為了實現 HTTP/2 的多路複用。流是伺服器和客戶端在 HTTP/2 連線內用於交換幀資料的獨立雙向序列,邏輯上可看做一個較為完整的互動處理單元,即表達一次完整的資源請求、響應資料交換流程。
型別 |
說明 |
簡單 RPC |
客戶端傳入一個請求物件,服務端返回一個結果物件 |
客戶端流式 RPC |
客戶端傳入多個請求物件,服務端返回一個結果物件 |
服務端流式 RPC |
客戶端傳入一個請求物件,服務端返回多個結果物件 |
雙向流式 RPC |
客戶端傳入多個請求物件,服務端返回多個結果物件 |
具體可以用法看一下官方文件,後面出一篇文章詳細說一下流式呼叫,各位大俠敬請期待
如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的“推薦”將是我最大的寫作動力!
本文版權歸作者和部落格園共有,來源網址:https://www.cnblogs.com/DanielYao/歡迎各位轉載,但是未經作者本人同意,轉載文章之後必須在文章頁面明顯位置給出作者和原文連線,否則保留追究法律責任的權利。