聊聊Grpc使用中的坑以及怎麼填

孫悟豬發表於2020-05-19

總所周知,隨著雲技術的發展,和業務的複雜度的上升,越來越多的系統開始拆分成獨立的子模組微服務。模組之間免不了相互通訊。但是隨著業務量的增多,傳輸量也隨之增大,偶發性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/歡迎各位轉載,但是未經作者本人同意,轉載文章之後必須在文章頁面明顯位置給出作者和原文連線,否則保留追究法律責任的權利

 

 

相關文章