双队列
§4 gRPC 总览 · 本专题 grpc/02(H2 2.x)。
async_grpc 核心:Completion Queue(CQ) 与 Event Queue(EQ) 分离 — gRPC I/O 与 Handler 业务分属不同线程池,经 RpcEvent 传递。
2.1 动机与职责
同步 gRPC server 每 RPC 一线程;Bridge 多客户端并发 SendNavigationCommand(Server Streaming)不可接受。官方在 libgrpc 异步 CQ 之上增加 EQ,用固定 \(N_{\text{cq}} + N_{\text{eq}}\) 线程 Multiplex 连接。
队列 |
线程 |
职责 |
阻塞容忍 |
|---|---|---|---|
Completion Queue |
|
网络 I/O、Protobuf 编解码 |
极低 |
Event Queue |
|
|
中等(可等 Navigator) |
单 Rpc 单线程:同一 RPC 内 Handler 不必 thread-safe;跨 Rpc 共享状态用 ExecutionContext(grpc/06 §6.4)。
2.2 数据流
Client ──HTTP/2──► CQ 线程 (Next → PushToEventQueue)
│
▼
EQ 线程 (Pop → RpcEvent::Handle → OnRequest / Send / Finish)
│
▼
SendNavigationHandler → Navigator
Send() / GetWriter() 触发 WRITE_NEEDED,直注 EQ、绕过 CQ(grpc/06 §6.6)。
2.3 Server 启动
Server::Start()(server.cpp):BuildAndStart() → 各 Service::StartServing → 预注册 idle Rpc(\(N_{\text{idle}} = N_{\text{cq}} \times M_{\text{methods}}\))→ 启动 EQ 线程 → 启动 CQ 线程。
Bridge 默认 2 方法 × 4 CQ = 8 个常驻 idle Rpc。
2.4 线程模型
线程池 |
循环 |
关键调用 |
|---|---|---|
CQ |
|
|
EQ |
|
|
EventQueueSelector Round-Robin 将新 Rpc 绑定到某一 EQ,保证单 Rpc 生命周期内线程固定。
2.5 事件类型
Event |
来源 |
含义 |
|---|---|---|
|
CQ |
客户端发起 RPC |
|
CQ |
收到请求(Client/Bidi Stream) |
|
EQ 内部 |
|
|
CQ |
Write/Finish 完成、连接销毁 |
2.6 ActiveRpcs
Service 维护 active_rpcs_:HandleNewConnection 时 OnConnection() 实例化 Handler → Clone() 预注册下一 idle Rpc → RequestNextMethodInvocation()。
2.7 吞吐与线程配置
Event 线程吞吐 \(\mu \approx N_{\text{event}} / T_h\)。Bridge 建议 \(N_{\text{event}} \geq N_{\text{grpc}}\),\(N_{\text{grpc}} \approx \lceil \text{CPU}/2 \rceil\)(见 §4.4)。
2.8 Shutdown
StopServing → server_->Shutdown() → join CQ → join EQ。GrpcBridgeServer 另 join task_thread_。