聊聊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

客戶端傳入多個請求對象,服務端返回多個結果對象

 

具體可以用法看一下官方文檔,後面出一篇文章詳細說一下流式調用,各位大俠敬請期待

 

 
Tags: