gRPC源碼分析 同步RPC請求與completion queue分析

gRPC completion queue架構

gRPC cq原理圖

 

  • grpc使用completion_queue來緩存事件,典型的如rpc請求。
  • 使用grpc_cq_end_op來向cq中加入事件,使用grpc_completion_queue_next或pluck從隊列中取出事件。
  • 其中next/pluck的區別是:next從隊列中按順序依次取出事件,pluck可以通過指定tag條件來獲取特定的事件.

 

接下來,我們通過同步RPC請求的處理流程,來了解下completion_queue的具體使用。

  • 對於grpc_server,啓動時會根據配置使用指定個數個cq來處理RPC請求,默認爲1.
  • 對於每個cq會啓動一個ThreadManager(線程池)來處理,其中使用1~CPU核心個線程來處理epoll請求,再使用其它動態線程來處理具體的RPC方法。
  • 對於grpc_server中註冊的每個RPC方法,都會用register_method來管理,每個register_method都有一個request_matcher用來跟蹤接收到的RPC請求

request_matcher跟蹤RPC請求的方式如下:

  1. 內部維護固定個數個令牌(令牌個數和cq個數相同),如果請求到達時還有令牌,則指定放入cq隊列中。如果令牌當前已經消耗完,則放入隊列中待處理(請求處於pending狀態).
  2. grpc_server每次接收到RPC請求時都會申請令牌,實際處理RPC方法時,再歸還令牌,同時判斷是否有pending狀態的請求待處理。
  3. 通過這種機制,對RPC請求進行了一定的流控。

上面提到的各種對象關係如下圖所示:

 

下面再來看一下,RPC請求到達時如何使用隊列。

涉及到對象的整體關係如下:

一個cq通常由3部分組成

  1. grpc_completion_queue結構頭,用於存儲隊列的管理信息.
  2. completion_queue_data,隊列數據存儲。內部通過grpc_cq_event_queue來存儲事件。這個隊列是一個MPSC(多生產者單一消費者隊列),只有一個消費者時是無鎖的,性能較高。有多個消費者時會使用鎖來進行同步
  3. grpc_pollset用於管理關心的fd, 驅動事件循環

當有RPC請求到來時,通過grpc_cq_end_op將RPC請求封裝成grpc_cq_completion放入隊列,如果是隊列中第一個事件,則會調用grpc_pollset的kick來喚醒一個工作者來完成任務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章