PeeringState 状态管理机制与关联关系分析
1. 概述
PeeringState 是 Ceph OSD 中 PG(Placement Group)对等(Peering)过程的核心状态机实现。它使用 boost::statechart 库实现了一个层次化的状态机,负责管理 PG 从初始化到激活、从 Peering 到 Active 的完整生命周期。
1.1 核心职责
- 状态转换管理:管理 PG 在不同状态间的转换
- Peering 协调:协调主副本和副本之间的信息交换
- 恢复触发:触发和协调恢复(Recovery)和回填(Backfill)流程
- 事件处理:处理 OSDMap 变化、消息接收等事件
1.2 设计特点
- 层次化状态:使用 boost::statechart 的层次状态机
- 事件驱动:通过事件触发状态转换
- 回调机制:通过 PeeringListener 与上层(PG)交互
2. 状态机架构
2.1 状态机层次结构
1 | PeeringMachine (状态机根) |
2.2 状态机类定义
1 | class PeeringMachine : public boost::statechart::state_machine< |
3. 状态定义与转换
3.1 主要状态说明
Initial(初始状态)
- 作用:状态机的起始状态
- 转换:
Initialize→ResetMNotifyRec→Primary(如果收到 Notify 消息)MInfoRec/MLogRec→Stray(如果收到 Info/Log 消息)
Reset(重置状态)
- 作用:重置 PG 状态,准备新的 Peering 过程
- 转换:
AdvMap→ 可能触发新的 PeeringActMap→ 激活 Map
Started(已启动状态)
- 作用:PG 已启动,等待确定角色(主副本/副本/游离)
- 子状态:
Start - 转换:
MakePrimary→PrimaryMakeStray→Stray
Primary(主副本状态)
- 作用:当前 OSD 是主副本
- 子状态:
Peering或Active - 处理事件:
ActMap:激活 MapMNotifyRec:处理副本 Notify 消息
Peering(对等状态)
- 作用:主副本正在与副本进行对等,交换信息
- 子状态:
GetInfo:获取副本信息GetLog:获取副本日志GetMissing:获取缺失对象信息WaitUpThru:等待 UpThruIncomplete:不完整状态
- 转换:
Activate→Active(对等完成,激活)
Active(激活状态)
- 作用:PG 已激活,可以处理客户端请求
- 子状态:
Activating:激活中Clean:干净状态(所有数据一致)Recovered:已恢复Backfilling:回填中Recovering:恢复中- 各种等待预留的状态
- 处理事件:
ActMap:激活 MapAdvMap:推进 MapMInfoRec:处理 Info 消息MLogRec:处理 Log 消息DoRecovery:开始恢复Backfilled:回填完成
ReplicaActive(副本激活状态)
- 作用:副本已激活
- 子状态:
RepNotRecovering:副本未恢复RepRecovering:副本恢复中RepWaitBackfillReserved:等待回填预留RepWaitRecoveryReserved:等待恢复预留
Stray(游离状态)
- 作用:PG 不在 acting/up set 中,等待删除
ToDelete(待删除状态)
- 作用:PG 标记为待删除
- 子状态:
WaitDeleteReserved:等待删除预留Deleting:删除中
3.2 状态转换示例
正常启动流程
1 | Initial |
恢复流程
1 | Active/Clean |
4. 事件系统
4.1 事件类型
Map 相关事件
AdvMap:OSDMap 推进事件
- 触发条件:OSDMap epoch 增加
- 处理:更新 up/acting set,可能触发新的 Peering
ActMap:OSDMap 激活事件
- 触发条件:OSDMap 激活
- 处理:激活 Map,更新状态
Peering 相关事件
MNotifyRec:收到 Notify 消息
- 来源:副本发送
- 处理:更新副本信息
MInfoRec:收到 Info 消息
- 来源:副本发送
- 处理:更新副本 PG 信息
MLogRec:收到 Log 消息
- 来源:副本发送
- 处理:更新副本日志
MQuery:收到 Query 消息
- 来源:主副本查询
- 处理:响应查询请求
激活相关事件
Activate:激活事件
- 触发条件:Peering 完成
- 处理:激活 PG
ActivateCommitted:激活已提交
- 触发条件:激活事务已提交
- 处理:完成激活流程
AllReplicasActivated:所有副本已激活
- 触发条件:所有副本都激活
- 处理:进入 Clean 状态
恢复相关事件
DoRecovery:开始恢复
- 触发条件:检测到需要恢复的对象
- 处理:请求恢复资源,开始恢复
RecoveryDone:恢复完成
- 触发条件:所有对象恢复完成
- 处理:进入 Recovered 状态
Backfilled:回填完成
- 触发条件:回填完成
- 处理:进入 Recovered 状态
其他事件
- QueryState:查询状态
- QueryUnfound:查询未找到的对象
- IntervalFlush:区间刷新
- RenewLease:续约租约
- CheckReadable:检查可读性
4.2 事件处理机制
1 | // 事件处理示例 |
5. 与外部组件的关联
5.1 与 PG 的关联
PeeringState 通过 PeeringListener 接口与 PG 交互:
1 | struct PeeringListener { |
关联方式:
PG实现PeeringListener接口PeeringState通过pl指针调用回调- 所有回调在 PG 锁保护下执行
5.2 与 OSDMap 的关联
1 | class PeeringState { |
关联方式:
PeeringState持有OSDMapRefAdvMap/ActMap事件携带新的 OSDMap- 状态转换时更新 OSDMap 引用
5.3 与 PGLog 的关联
1 | class PeeringState { |
关联方式:
PeeringState直接管理pg_log- Peering 过程中比对和合并日志
- 日志用于确定缺失对象
5.4 与 MissingLoc 的关联
1 | class PeeringState : public MissingLoc::MappingInfo { |
关联方式:
PeeringState继承MissingLoc::MappingInfomissing_loc用于定位缺失对象的位置- 恢复流程使用
missing_loc确定恢复源
5.5 与 PeeringCtx 的关联
1 | struct PeeringCtx : BufferedRecoveryMessages { |
关联方式:
- 每个状态转换使用
PeeringCtx管理上下文 transaction用于批量提交状态变更BufferedRecoveryMessages用于缓冲消息
5.6 与 OSDService 的关联
通过 PeeringListener 间接关联:
1 | // PG 实现 PeeringListener |
6. 状态管理机制
6.1 状态进入/退出
每个状态都有 enter() 和 exit() 方法:
1 | struct Active : boost::statechart::state< Active, Primary, Activating > { |
6.2 状态标志管理
PeeringState 使用位标志管理 PG 状态:
1 | class PeeringState { |
状态标志包括:
PG_STATE_ACTIVE:激活PG_STATE_PEERED:已对等PG_STATE_CLEAN:干净PG_STATE_DEGRADED:降级PG_STATE_RECOVERING:恢复中PG_STATE_BACKFILLING:回填中PG_STATE_UNDERSIZED:大小不足- 等等
6.3 状态历史记录
1 | class PGStateHistory { |
用途:
- 记录状态转换历史
- 性能统计(每个状态的停留时间)
- 调试和问题排查
6.4 事件处理流程
1 | // 1. 接收事件 |
7. 关键状态转换场景
7.1 OSDMap 变化场景
1 | 1. OSDMap 更新(AdvMap 事件) |
7.2 Peering 完成场景
1 | 1. 收集所有副本信息(GetInfo) |
7.3 恢复触发场景
1 | 1. 检测到缺失对象(needs_recovery) |
7.4 回填触发场景
1 | 1. 检测到需要回填(needs_backfill) |
8. 状态同步机制
8.1 主副本与副本的同步
主副本:
- 发送
MOSDPGInfo2消息(包含 PG 信息) - 发送
MOSDPGLog消息(包含日志) - 接收副本的
MOSDPGNotify2消息
副本:
- 发送
MOSDPGNotify2消息(通知主副本) - 接收主副本的
MOSDPGInfo2和MOSDPGLog消息 - 根据主副本的信息更新本地状态
8.2 状态一致性保证
版本控制:
- 使用
eversion_t管理对象版本 - 日志条目包含版本信息
- 通过版本比对确定一致性
- 使用
事务提交:
- 状态变更通过事务提交
- 事务提交后才真正生效
- 支持回滚机制
消息顺序:
- 使用 epoch 确保消息顺序
- 丢弃过期的消息
- 保证状态转换的原子性
9. 性能优化
9.1 状态转换优化
- 批量处理:多个状态变更批量提交
- 延迟激活:某些状态转换延迟执行
- 资源预留:提前预留恢复/回填资源
9.2 消息缓冲
1 | struct BufferedRecoveryMessages { |
优势:
- 减少消息发送次数
- 保证消息与状态的一致性
- 提高性能
9.3 状态历史统计
1 | class PGStateHistory { |
10. 错误处理
10.1 状态机错误
- Crashed 状态:处理无法恢复的错误
- 事件丢弃:丢弃无法处理的事件
- 状态回退:某些错误可能导致状态回退
10.2 超时处理
- Peering 超时:如果 Peering 长时间未完成,可能触发超时
- 恢复超时:恢复操作超时处理
- 消息超时:等待消息超时处理
10.3 异常恢复
- 状态不一致:检测并修复状态不一致
- 日志损坏:处理日志损坏情况
- 数据丢失:处理数据丢失情况
11. 总结
11.1 核心机制
- 层次化状态机:使用 boost::statechart 实现
- 事件驱动:通过事件触发状态转换
- 回调机制:通过 PeeringListener 与上层交互
- 事务管理:状态变更通过事务提交
- 消息缓冲:优化消息发送
11.2 关键关联
- PG:通过 PeeringListener 接口关联
- OSDMap:持有引用,响应 Map 变化
- PGLog:直接管理,用于 Peering
- MissingLoc:继承 MappingInfo,定位缺失对象
- PeeringCtx:管理状态转换上下文
- OSDService:通过 PG 间接关联
11.3 设计优势
- 清晰的状态管理:层次化状态机使状态转换清晰
- 解耦设计:通过接口与上层解耦
- 可扩展性:易于添加新状态和事件
- 可维护性:状态转换逻辑集中管理
- 可调试性:状态历史记录便于调试
11.4 相关文件
PeeringState.h/cc:状态机实现PGPeeringEvent.h/cc:事件定义PGStateUtils.h/cc:状态工具函数PG.cc:PG 实现 PeeringListenerOSD.cc:OSD 触发状态机事件
正在加载留言…