yanglimingcn commented on PR #3350:
URL: https://github.com/apache/brpc/pull/3350#issuecomment-4873879147
新连接到达 (epoll IN)
│
▼
InputMessenger::OnNewMessages(m)
│
▼
CutInputMessage(m, &index) // 遍历所有已注册 handler 的 parse 函数
│
├─ handler[0]: ParseBaiduStdMessage → PARSE_ERROR (不是 baidu_std)
├─ handler[1]: ParseHttpMessage → PARSE_ERROR (不是 http)
├─ ...
├─ handler[N]: ParseRdmaHandshake // ★ 新增的 RDMA handshake 协议
│ │
│ ├─ _read_buf 前 N 字节匹配 "RDMA" 或 "RDM3" magic?
│ │ ├─ YES → 返回 PARSE_OK + 设置 parsing_context = RdmaHandshake*
│ │ └─ NO → 返回 PARSE_ERROR_NOT_SAME
│ │
│ └─ [如果是 PARSE_OK]
│ ▼
│ ProcessRdmaHandshake(msg) // 服务端处理函数
│ │
│ ├─ 从 msg 中取出已解析的 hello 信息
│ ├─ AllocateResources() // QP/CQ
│ ├─ BringUpQp()
│ ├─ SendLocalHello() // 通过 Socket 写回
│ ├─ Read ACK
│ │
│ ├─ 成功 → 标记 socket 为 RDMA_ESTABLISHED
│ │ 后续数据走 RDMA CQ path
│ │
│ └─ 失败 → 返回错误码
│ InputMessenger 自动 fallback 到下一个协议
│ (因为 rdma_handshake 不是 preferred)
│
└─ 所有协议都失败 → 连接关闭
新连接到达 (epoll IN)
│
▼
InputMessenger::OnNewMessages(m)
│
▼
CutInputMessage(m, &index) // 遍历所有已注册 handler 的 parse 函数
│
├─ handler[0]: ParseBaiduStdMessage → PARSE_ERROR (不是 baidu_std)
├─ handler[1]: ParseHttpMessage → PARSE_ERROR (不是 http)
├─ ...
├─ handler[N]: ParseRdmaHandshake // ★ 新增的 RDMA handshake 协议
│ │
│ ├─ _read_buf 前 N 字节匹配 "RDMA" 或 "RDM3" magic?
│ │ ├─ YES → 返回 PARSE_OK + 设置 parsing_context = RdmaHandshake*
│ │ └─ NO → 返回 PARSE_ERROR_NOT_SAME
│ │
│ └─ [如果是 PARSE_OK]
│ ▼
│ ProcessRdmaHandshake(msg) // 服务端处理函数
│ │
│ ├─ 从 msg 中取出已解析的 hello 信息
│ ├─ AllocateResources() // QP/CQ
│ ├─ BringUpQp()
│ ├─ SendLocalHello() // 通过 Socket 写回
│ ├─ Read ACK
│ │
│ ├─ 成功 → 标记 socket 为 RDMA_ESTABLISHED
│ │ 后续数据走 RDMA CQ path
│ │
│ └─ 失败 → 返回错误码
│ InputMessenger 自动 fallback 到下一个协议
│ (因为 rdma_handshake 不是 preferred)
│
└─ 所有协议都失败 → 连接关闭
关键设计点
ParseRdmaHandshake 只做轻量级判断:检查 _read_buf 开头是否匹配 RDMA magic 字节。不阻塞、不分配资源。
ProcessRdmaHandshake 做重量级工作:但注意——当前 brpc 的 process_request 回调是不能做阻塞
I/O的(它在事件线程上运行)。所以 PR 可能有两种实现策略:
策略 A:ProcessRdmaHandshake 内部仍然启动一个 bthread(类似现在的
ProcessHandshakeAtServer),只是入口从 OnNewDataFromTcp 变成了协议分发。
策略 B:如果 handshake 数据已经在 ParseRdmaHandshake 阶段全部读入 _read_buf(RDMA handshake
本身很短,通常 < 1KB),那么 ProcessRdmaHandshake 可以同步完成,无需额外 bthread。
Fallback 天然优雅:
PR 之前:手动 s->_read_buf.append(magic, MAGIC_STR_LEN) 把字节放回去
PR 之后:ParseRdmaHandshake 返回 PARSE_ERROR_NOT_SAME,CutInputMessage 的 do-while
循环自动尝试下一个 handler(baidu_std、http 等),零拷贝、无手动回退
消除了 _state data race:不再需要 RdmaEndpoint::_state 来协调两个线程。协议分发的 preferred_index
和 parsing_context 由 InputMessenger 统一管理,本身就是为并发安全设计的。
@chenBright 有时间可以看一下这个分析是否靠谱。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]