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来唤醒一个工作者来完成任务。

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