Replies: 1 comment
|
@wwbmmm @chenBright @yanglimingcn 大佬们辛苦抽时间看看这块特性内容的建议,有什么建议或者想法欢迎交流请教... |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
1. 背景
brpc 当前有三种基于 TCP 建立控制连接、再切换到高速数据面的传输:
src/brpc/rdma/rdma_endpoint.*src/brpc/urma/urma_endpoint.*src/brpc/ubshm/ub_endpoint.*三套实现都包含以下流程:
目前公共流程主要以复制代码的形式存在。例如:
rdma_endpoint.cpp中实现;urma_endpoint.cpp中重新实现了一套;ub_endpoint.cpp中再次实现了一套;本方案只抽取握手公共组件,不尝试合并 RDMA QP、URMA Jetty 或 UBSHM ring 的数据面实现。
Related PRs
2. 现状分析
2.1 RDMA
RDMA 支持:
RDMAmagic;RDM3magic;butil::IOBuf的增量解析;相关代码:
src/brpc/rdma/rdma_handshake.hsrc/brpc/rdma/rdma_handshake.cppsrc/brpc/rdma/rdma_handshake_server.cpp2.2 URMA
URMA 的握手结构与 RDMA 类似,但 payload 完全不同:
URMAmagic;URM3magic;UrmaEndpoint自己驱动。相关代码:
src/brpc/urma/urma_handshake.hsrc/brpc/urma/urma_handshake.cppsrc/brpc/urma/urma_endpoint.cpp2.3 UBSHM/UBRING
UBSHM 当前使用固定长度二进制握手:
Hello 中携带:
msg_lenhello_verimpl_ver握手成功后,通过 ACK 中的
UB_OKbit 表示是否切换到 UBRING;失败时回退 TCP。相关代码:
src/brpc/ubshm/ub_endpoint.hsrc/brpc/ubshm/ub_endpoint.cpp:63src/brpc/ubshm/ub_endpoint.cpp:331src/brpc/ubshm/ub_endpoint.cpp:4603. 设计目标
IOBuf的增量读取。4. 总体架构
新增公共目录:
总体关系如下:
公共组件只负责握手过程和字节帧,不负责判断“创建 QP、导入 Jetty 还是映射 SHM”。
4.1 两种候选架构对比
本节同时保留两种方案,便于社区讨论握手组件应该放在哪一层。
方案 A:公共握手组件与各类 Endpoint 组合
这是上一版设计的方向:公共组件提供
HandshakeIO、FrameCodec和部分握手驱动,各类 Transport/Endpoint 负责组合调用。TCP fallback 仍由具体 Transport 维护,Endpoint 仍可能参与握手生命周期。flowchart TB Socket["Socket"] --> T["RdmaTransport / UrmaTransport / UBShmTransport"] T --> TCP["TcpTransport\nTCP fallback"] T --> HS["HandshakeSession\n公共握手驱动"] HS --> IO["HandshakeIO / FrameCodec"] HS --> EP["RdmaEndpoint / UrmaEndpoint / UBShmEndpoint"] EP --> EHS["Endpoint handshake callbacks\nBuildHello / ParseHello / Negotiate"] EP --> DP["高速数据面\nQP / Jetty / UBRing"] T --> FB["Transport fallback state"] FB --> TCP该方案可以先复用 frame 和 I/O 代码,改动较小;但握手生命周期仍然横跨 Transport 和 Endpoint,Endpoint 与 TCP 控制连接之间仍存在一定耦合。
方案 B:Handshake 放到 Transport 上层,Endpoint 只负责数据面
这是本次建议的方向:默认先建立 TCP 连接,客户端可以请求升级到 RDMA、URMA 或 UBSHM。握手、升级决策、fallback 和 active transport 选择全部由上层 Transport 负责。
flowchart TB Socket["Socket"] --> UT["UpgradeTransport / NegotiatingTransport"] UT --> TCP["TcpTransport\n默认控制面与 TCP 数据面"] UT --> HS["HandshakeSession\n连接协商 / 版本 / ACK / fallback"] HS --> IO["HandshakeIO + FrameCodec"] UT --> PF["UpgradeProvider\n选择协议与 Endpoint factory"] PF --> R["RdmaEndpoint\n仅高速数据面"] PF --> U["UrmaEndpoint\n仅高速数据面"] PF --> B["UBShmEndpoint\n仅高速数据面"] R --> RD["QP / CQ / MR"] U --> UD["Jetty / JFC / Segment"] B --> BD["UBRing / Shared Memory"] UT --> ST["TransportState\nTCP_ACTIVE / UPGRADING / HIGH_SPEED_ACTIVE"] ST --> TCP ST --> R ST --> U ST --> B方案 B 中,Endpoint 不再执行 TCP fd 读写、magic 判断、握手 bthread 或 TCP fallback。它只向 Transport 提供资源准备、Hello payload、远端参数应用和数据面操作。
两种方案的主要差异
flowchart LR A["方案 A\nHandshake 与 Endpoint 组合"] --> A1["公共代码复用较快"] A --> A2["Endpoint 仍参与连接控制"] A --> A3["Fallback 状态分散"] A --> A4["后续新增传输仍需接入 Endpoint 握手"] B["方案 B\nHandshake 位于 Transport"] --> B1["TCP 是统一默认控制面"] B --> B2["Endpoint 只负责高速数据面"] B --> B3["Fallback 与 active path 统一"] B --> B4["新增传输只需提供 Provider"]当前观点与社区讨论方向
两种方案的核心区别在于公共 Handshake 所处的架构层级。
方案 A:Endpoint 级复用 Handshake。
在现有架构基础上,将 RDMA、URMA、UBSHM 中重复的 Handshake 逻辑抽取为公共组件,由各自 Endpoint 进行复用。该方案主要解决当前握手代码重复的问题,整体改动较小,迁移风险相对较低;但 Handshake 仍然属于各 Endpoint 建链流程的一部分,Transport 层缺少统一的连接协商、Transport 切换和 fallback 能力。
方案 B:将 Handshake 提升到 Transport 级。
默认先建立 TCP 连接,以 TCP 作为统一的控制通道,通过 TCP 交换双方的能力信息以及目标高速通道建链所需的信息;协商成功后,再将连接从 TCP 升级到 RDMA、URMA、UBSHM 等目标 Transport。Endpoint 则进一步收敛为具体高速数据面的实现,不再承担通用的 TCP Handshake、Transport 协商和 fallback 职责。
目前我们更倾向于 方案 B。
相比单纯在 Endpoint 层复用 Handshake 代码,方案 B 将“Transport 协商与升级”本身抽象为统一能力。TCP 可以作为默认的控制面,在 Transport 层统一完成能力协商、建链信息交换、Transport 升级以及失败后的 fallback,而各 Endpoint 只需要关注对应高速数据面的资源管理和数据传输。
这种方式不仅能够解决当前 RDMA、URMA、UBSHM 之间 Handshake 逻辑重复的问题,也为后续 Transport 能力演进提供了更大的扩展空间。
特别是未来如果需要支持多个 Transport、多个可用数据路径,或者根据双方能力、链路状态等信息进行多路径选择,可以继续在 Transport 层扩展统一的协商和选择机制,而不需要分别在 RDMA、URMA、UBSHM 等 Endpoint 中重复实现类似逻辑。
因此,我们目前更倾向于方案 B,同时希望听取社区对这一架构方向的意见:
4.2 方案 B 的连接升级时序
客户端请求高速传输
sequenceDiagram participant C as Client participant T as UpgradeTransport participant TCP as TcpTransport participant H as HandshakeSession participant E as High-speed Endpoint participant S as Server Transport C->>T: Connect() T->>TCP: Establish TCP connection TCP-->>T: TCP connected T->>H: StartClient() H->>TCP: Send high-speed Hello TCP->>S: Hello over TCP S->>S: Select RDMA / URMA / UBSHM provider S-->>TCP: Remote Hello TCP-->>H: Receive Remote Hello H->>E: Parse remote parameters / prepare resources E-->>H: Resource negotiation result alt Upgrade succeeds H->>TCP: Send enabled ACK H->>T: NEGOTIATED T->>E: Activate() T-->>C: Connect done, high-speed active else Upgrade unavailable or resource failure H->>TCP: Send disabled ACK H->>T: FALLBACK T-->>C: Connect done, TCP active end服务端识别客户端请求
sequenceDiagram participant TCP as TcpTransport participant T as UpgradeTransport participant H as HandshakeSession participant E as Selected Endpoint participant IM as InputMessenger TCP->>T: TCP readable event T->>T: Peek magic alt Magic matches upgrade protocol T->>H: Create protocol handshake H->>T: Consume Hello frame H->>E: Parse and negotiate resources alt Negotiation succeeds E-->>H: Ready H->>T: Activate endpoint T->>E: Future data events else Negotiation fails H->>T: Fallback to TCP T->>IM: Continue normal TCP parsing end else Magic does not match T->>T: Push back inspected bytes T->>IM: Continue normal TCP parsing endAll reactions