Ceph Crimson 网络调用和消息派发到OSD Shard分析
概述
本文档分析Ceph Crimson中网络层如何被调用,以及消息如何从网络层派发到OSD的shard的完整流程。
1. 网络层架构
1.1 核心组件
- SocketMessenger: 消息传递器,管理连接和消息路由
- SocketConnection: 表示一个网络连接
- IOHandler: 处理连接的I/O操作(读/写消息)
- ProtocolV2: 实现Ceph消息协议V2版本
- FrameAssemblerV2: 负责消息帧的组装和解析
- ChainedDispatchers: 链式分发器,将消息分发给多个Dispatcher
1.2 Shard管理
Crimson使用Seastar的shard模型,每个shard是一个独立的执行上下文(通常对应一个CPU核心)。网络连接可以在不同的shard之间迁移。
2. 网络监听和连接建立
2.1 启动监听
1 | SocketMessenger::start( |
流程:
SocketMessenger::start()被调用,传入dispatchers列表- 如果已绑定地址,调用
ShardedServerSocket::accept()开始接受连接 ShardedServerSocket在所有shard上创建监听器(如果dispatch_only_on_this_shard=false)
2.2 接受连接
1 | seastar::future<> |
当新连接到达时:
ShardedServerSocket::accept()在循环中接受连接- 创建
Socket对象 - 调用
fn_accept回调(由SocketMessenger::accept()提供) SocketMessenger::accept()创建SocketConnection并开始握手
3. 消息读取流程
3.1 启动消息读取
当连接建立并完成握手后,IOHandler 开始读取消息:
1 | void IOHandler::do_in_dispatch() |
流程:
do_in_dispatch()进入消息读取循环- 调用
frame_assembler->read_main_preamble()读取消息头 - 根据消息类型(MESSAGE、ACK、KEEPALIVE等)进行不同处理
- 对于MESSAGE类型,调用
read_message()读取完整消息
3.2 读取和解析消息
1 | seastar::future<> |
关键步骤:
- 读取消息帧的payload
- 解码消息头(
MessageFrame::Decode) - 调用
decode_message()创建Message对象 - 验证消息序列号
- 调用
dispatchers.ms_dispatch()派发消息
4. 消息派发到Dispatcher
4.1 ChainedDispatchers派发
1 | seastar::future<> |
ChainedDispatchers 按顺序遍历所有dispatchers:
- 如果某个dispatcher返回非空的future,表示它处理了该消息,停止遍历
- 如果所有dispatchers都不处理,记录错误
4.2 OSD的Dispatcher实现
1 | std::optional<seastar::future<>> |
OSD的 ms_dispatch() 实现:
- 检查OSD是否正在停止
- 调用
do_ms_dispatch()处理消息 - 如果返回future,在后台执行
4.3 跨Shard消息处理
1 | std::optional<seastar::future<>> |
重要机制:
- 如果消息不在PRIMARY_CORE上,某些消息类型(如OSD_MAP)会被转发到PRIMARY_CORE
- 使用
seastar::smp::submit_to()跨shard提交任务
5. Shard迁移机制
5.1 连接迁移到新Shard
1 | seastar::future<> |
Shard迁移流程:
- 在旧shard上:保存当前状态,通知dispatchers shard变化
- 创建新shard的状态对象
- 提交任务到新shard
- 在新shard上:恢复连接引用,通知dispatchers连接已迁移
6. 消息发送流程
6.1 发送消息
1 | seastar::future<> IOHandler::send(MessageURef _msg) |
发送流程:
- 如果调用者不在连接的shard上,使用
smp::submit_to()提交到正确的shard - 调用
do_send()将消息加入发送队列 - 通知输出调度器开始发送
7. 关键数据结构
7.1 Shard States
1 | class shard_states_t { |
shard_states_t 管理每个shard的状态:
io_state: delay/open/drop/switchedgate: 用于同步后台任务out_dispatching/in_dispatching: 跟踪I/O调度状态
8. 总结
8.1 消息接收流程
- 网络层接受连接 →
ShardedServerSocket::accept() - 创建连接对象 →
SocketMessenger::accept()→SocketConnection - 握手完成 →
ProtocolV2完成握手 - 启动消息读取 →
IOHandler::do_in_dispatch() - 读取消息帧 →
FrameAssemblerV2::read_main_preamble() - 解析消息 →
IOHandler::read_message() - 派发给Dispatcher →
ChainedDispatchers::ms_dispatch() - OSD处理消息 →
OSD::ms_dispatch()→OSD::do_ms_dispatch()
8.2 Shard分配机制
- 连接可以在不同shard之间迁移
- 使用
seastar::smp::submit_to()跨shard提交任务 - 每个shard维护独立的状态(
shard_states_t) - OSD的某些消息必须在PRIMARY_CORE上处理
8.3 关键设计点
- 异步I/O: 所有网络操作都是异步的,使用Seastar的future/promise模型
- Shard隔离: 每个shard独立处理,避免锁竞争
- 状态管理: 使用状态机管理连接和I/O状态
- 错误处理: 完善的异常处理和连接恢复机制
正在加载留言…