PeeringState 状态管理机制与关联关系分析

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
PeeringMachine (状态机根)

├── Initial (初始状态)
│ └── 转换到 Reset

├── Reset (重置状态)
│ └── 转换到 Started

├── Started (已启动状态)
│ ├── Start (启动子状态)
│ │ ├── 转换到 Primary (主副本)
│ │ └── 转换到 Stray (游离副本)
│ │
│ ├── Primary (主副本状态)
│ │ ├── WaitActingChange (等待 Acting 变更)
│ │ ├── Peering (对等状态)
│ │ │ ├── GetInfo (获取信息)
│ │ │ ├── GetLog (获取日志)
│ │ │ ├── GetMissing (获取缺失对象)
│ │ │ ├── WaitUpThru (等待 UpThru)
│ │ │ └── Incomplete (不完整)
│ │ │
│ │ └── Active (激活状态)
│ │ ├── Activating (激活中)
│ │ ├── Clean (干净状态)
│ │ ├── Recovered (已恢复)
│ │ ├── Backfilling (回填中)
│ │ ├── WaitRemoteBackfillReserved (等待远程回填预留)
│ │ ├── WaitLocalBackfillReserved (等待本地回填预留)
│ │ ├── NotBackfilling (未回填)
│ │ ├── NotRecovering (未恢复)
│ │ ├── Recovering (恢复中)
│ │ ├── WaitRemoteRecoveryReserved (等待远程恢复预留)
│ │ └── WaitLocalRecoveryReserved (等待本地恢复预留)
│ │
│ ├── ReplicaActive (副本激活状态)
│ │ ├── RepNotRecovering (副本未恢复)
│ │ ├── RepRecovering (副本恢复中)
│ │ ├── RepWaitBackfillReserved (副本等待回填预留)
│ │ └── RepWaitRecoveryReserved (副本等待恢复预留)
│ │
│ ├── Stray (游离状态)
│ │
│ └── ToDelete (待删除状态)
│ ├── WaitDeleteReserved (等待删除预留)
│ └── Deleting (删除中)

└── Crashed (崩溃状态)

2.2 状态机类定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class PeeringMachine : public boost::statechart::state_machine< 
PeeringMachine,
Initial // 初始状态
> {
PeeringState *state; // 关联的 PeeringState
PGStateHistory *state_history; // 状态历史记录
CephContext *cct; // Ceph 上下文
spg_t spgid; // PG ID
DoutPrefixProvider *dpp; // 日志前缀提供者
PeeringListener *pl; // 监听器(通常是 PG)

utime_t event_time; // 事件处理时间
uint64_t event_count; // 事件计数
};

3. 状态定义与转换

3.1 主要状态说明

Initial(初始状态)

  • 作用:状态机的起始状态
  • 转换
    • InitializeReset
    • MNotifyRecPrimary(如果收到 Notify 消息)
    • MInfoRec / MLogRecStray(如果收到 Info/Log 消息)

Reset(重置状态)

  • 作用:重置 PG 状态,准备新的 Peering 过程
  • 转换
    • AdvMap → 可能触发新的 Peering
    • ActMap → 激活 Map

Started(已启动状态)

  • 作用:PG 已启动,等待确定角色(主副本/副本/游离)
  • 子状态Start
  • 转换
    • MakePrimaryPrimary
    • MakeStrayStray

Primary(主副本状态)

  • 作用:当前 OSD 是主副本
  • 子状态PeeringActive
  • 处理事件
    • ActMap:激活 Map
    • MNotifyRec:处理副本 Notify 消息

Peering(对等状态)

  • 作用:主副本正在与副本进行对等,交换信息
  • 子状态
    • GetInfo:获取副本信息
    • GetLog:获取副本日志
    • GetMissing:获取缺失对象信息
    • WaitUpThru:等待 UpThru
    • Incomplete:不完整状态
  • 转换
    • ActivateActive(对等完成,激活)

Active(激活状态)

  • 作用:PG 已激活,可以处理客户端请求
  • 子状态
    • Activating:激活中
    • Clean:干净状态(所有数据一致)
    • Recovered:已恢复
    • Backfilling:回填中
    • Recovering:恢复中
    • 各种等待预留的状态
  • 处理事件
    • ActMap:激活 Map
    • AdvMap:推进 Map
    • MInfoRec:处理 Info 消息
    • MLogRec:处理 Log 消息
    • DoRecovery:开始恢复
    • Backfilled:回填完成

ReplicaActive(副本激活状态)

  • 作用:副本已激活
  • 子状态
    • RepNotRecovering:副本未恢复
    • RepRecovering:副本恢复中
    • RepWaitBackfillReserved:等待回填预留
    • RepWaitRecoveryReserved:等待恢复预留

Stray(游离状态)

  • 作用:PG 不在 acting/up set 中,等待删除

ToDelete(待删除状态)

  • 作用:PG 标记为待删除
  • 子状态
    • WaitDeleteReserved:等待删除预留
    • Deleting:删除中

3.2 状态转换示例

正常启动流程

1
2
3
4
5
6
7
8
9
10
Initial
→ (Initialize) → Reset
→ (AdvMap) → Started/Start
→ (MakePrimary) → Primary/Peering/GetInfo
→ (GotInfo) → GetLog
→ (GotLog) → GetMissing
→ (GotMissing) → Active/Activating
→ (ActivateCommitted) → Active/Recovering
→ (RecoveryDone) → Active/Recovered
→ (GoClean) → Active/Clean

恢复流程

1
2
3
4
5
6
Active/Clean
→ (DoRecovery) → Active/WaitLocalRecoveryReserved
→ (LocalRecoveryReserved) → Active/WaitRemoteRecoveryReserved
→ (AllRecoveryReserved) → Active/Recovering
→ (RecoveryDone) → Active/Recovered
→ (GoClean) → 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 事件处理示例
boost::statechart::result PeeringState::Active::react(const AdvMap& advmap) {
// 1. 检查是否需要重启 Peering
if (should_restart_peering(...)) {
return forward_event(); // 转发事件到父状态
}

// 2. 处理 Map 变化
pl->on_active_advmap(advmap.osdmap);

// 3. 更新状态
pl->publish_stats_to_osd();

return forward_event(); // 继续处理
}

5. 与外部组件的关联

5.1 与 PG 的关联

PeeringState 通过 PeeringListener 接口与 PG 交互:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct PeeringListener {
// 准备写入
virtual void prepare_write(...) = 0;

// 恢复回调
virtual void on_local_recover(...) = 0;
virtual void on_global_recover(...) = 0;
virtual void on_peer_recover(...) = 0;

// 状态变更回调
virtual void on_activate(...) = 0;
virtual void on_active_advmap(...) = 0;

// 消息发送
virtual void send_cluster_message(...) = 0;

// 事务提交
virtual void queue_transaction(...) = 0;

// 统计发布
virtual void publish_stats_to_osd() = 0;
};

关联方式

  • PG 实现 PeeringListener 接口
  • PeeringState 通过 pl 指针调用回调
  • 所有回调在 PG 锁保护下执行

5.2 与 OSDMap 的关联

1
2
3
4
5
6
7
8
9
10
11
12
class PeeringState {
OSDMapRef osdmap_ref; // 当前 OSDMap 引用

// 更新 OSDMap
void update_osdmap_ref(OSDMapRef newmap);

// 处理 Map 推进
void advance_map(OSDMapRef osdmap, ...);

// 处理 Map 激活
void activate_map(PeeringCtx &rctx);
};

关联方式

  • PeeringState 持有 OSDMapRef
  • AdvMap / ActMap 事件携带新的 OSDMap
  • 状态转换时更新 OSDMap 引用

5.3 与 PGLog 的关联

1
2
3
4
5
6
7
8
9
class PeeringState {
PGLog pg_log; // PG 日志

// 日志操作
void merge_log(...); // 合并日志
void rewind_divergent_log(...); // 回退分歧日志
void append_log(...); // 追加日志
void add_log_entry(...); // 添加日志条目
};

关联方式

  • PeeringState 直接管理 pg_log
  • Peering 过程中比对和合并日志
  • 日志用于确定缺失对象

5.4 与 MissingLoc 的关联

1
2
3
4
5
6
7
class PeeringState : public MissingLoc::MappingInfo {
MissingLoc missing_loc; // 缺失对象定位器

// 缺失对象管理
void build_might_have_unfound(); // 构建可能包含未找到对象的集合
void discover_all_missing(...); // 发现所有缺失对象
};

关联方式

  • PeeringState 继承 MissingLoc::MappingInfo
  • missing_loc 用于定位缺失对象的位置
  • 恢复流程使用 missing_loc 确定恢复源

5.5 与 PeeringCtx 的关联

1
2
3
4
5
6
7
8
9
struct PeeringCtx : BufferedRecoveryMessages {
ObjectStore::Transaction transaction; // 事务
HBHandle* handle; // 心跳句柄

// 消息缓冲
void send_notify(...);
void send_query(...);
void send_info(...);
};

关联方式

  • 每个状态转换使用 PeeringCtx 管理上下文
  • transaction 用于批量提交状态变更
  • BufferedRecoveryMessages 用于缓冲消息

5.6 与 OSDService 的关联

通过 PeeringListener 间接关联:

1
2
3
4
5
6
7
8
9
10
11
12
// PG 实现 PeeringListener
class PG : public PeeringState::PeeringListener {
OSDService *osd; // OSD 服务

void send_cluster_message(...) {
osd->send_message_osd_cluster(...);
}

void queue_transaction(...) {
osd->store->queue_transaction(...);
}
};

6. 状态管理机制

6.1 状态进入/退出

每个状态都有 enter()exit() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Active : boost::statechart::state< Active, Primary, Activating > {
explicit Active(my_context ctx) {
// 进入状态时的初始化
context< PeeringMachine >().log_enter(state_name);

// 激活 PG
ps->activate(transaction, epoch, ctx);

// 初始化恢复状态
ps->blocked_by.clear();
}

void exit() {
// 退出状态时的清理
context< PeeringMachine >().log_exit(state_name, enter_time);

// 清除状态标志
ps->state_clear(PG_STATE_ACTIVE);
}
};

6.2 状态标志管理

PeeringState 使用位标志管理 PG 状态:

1
2
3
4
5
6
7
8
9
10
11
12
class PeeringState {
pg_state_t state; // PG 状态标志

// 设置状态标志
void state_set(pg_state_t s) { state |= s; }

// 清除状态标志
void state_clear(pg_state_t s) { state &= ~s; }

// 检查状态标志
bool state_test(pg_state_t s) const { return state & s; }
};

状态标志包括

  • PG_STATE_ACTIVE:激活
  • PG_STATE_PEERED:已对等
  • PG_STATE_CLEAN:干净
  • PG_STATE_DEGRADED:降级
  • PG_STATE_RECOVERING:恢复中
  • PG_STATE_BACKFILLING:回填中
  • PG_STATE_UNDERSIZED:大小不足
  • 等等

6.3 状态历史记录

1
2
3
4
5
6
7
8
9
10
11
12
class PGStateHistory {
struct StateEntry {
const char *state_name;
utime_t enter_time;
utime_t exit_time;
};

std::list<StateEntry> history;

void log_enter(const char *name);
void log_exit(const char *name, utime_t duration);
};

用途

  • 记录状态转换历史
  • 性能统计(每个状态的停留时间)
  • 调试和问题排查

6.4 事件处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1. 接收事件
void PeeringState::handle_event(const Event &evt, PeeringCtx *ctx) {
start_handle(ctx);
machine.process_event(evt); // 状态机处理事件
end_handle();
}

// 2. 状态机路由事件
boost::statechart::result State::react(const Event &evt) {
// 处理事件
// 返回转换结果
return transit<NextState>(); // 转换到下一状态
// 或
return discard_event(); // 丢弃事件
// 或
return forward_event(); // 转发到父状态
}

7. 关键状态转换场景

7.1 OSDMap 变化场景

1
2
3
4
5
6
7
8
9
10
11
12
1. OSDMap 更新(AdvMap 事件)

2. 检查是否需要重启 Peering

3. 如果需要:
- 转换到 Reset
- 开始新的 Peering 流程

4. 如果不需要:
- 更新对等节点信息
- 移除已下线的节点
- 继续当前状态

7.2 Peering 完成场景

1
2
3
4
5
6
7
8
9
10
11
1. 收集所有副本信息(GetInfo)

2. 获取权威日志(GetLog)

3. 计算缺失对象(GetMissing)

4. 选择 Acting Set(choose_acting)

5. 发送 Activate 事件

6. 转换到 Active 状态

7.3 恢复触发场景

1
2
3
4
5
6
7
8
9
10
11
12
13
1. 检测到缺失对象(needs_recovery)

2. 发送 DoRecovery 事件

3. 请求恢复资源(WaitLocalRecoveryReserved)

4. 等待远程资源(WaitRemoteRecoveryReserved)

5. 开始恢复(Recovering)

6. 恢复完成(RecoveryDone)

7. 转换到 Recovered 状态

7.4 回填触发场景

1
2
3
4
5
6
7
8
9
10
11
12
13
1. 检测到需要回填(needs_backfill)

2. 发送 RequestBackfill 事件

3. 请求本地资源(WaitLocalBackfillReserved)

4. 等待远程资源(WaitRemoteBackfillReserved)

5. 开始回填(Backfilling)

6. 回填完成(Backfilled)

7. 转换到 Recovered 状态

8. 状态同步机制

8.1 主副本与副本的同步

主副本

  • 发送 MOSDPGInfo2 消息(包含 PG 信息)
  • 发送 MOSDPGLog 消息(包含日志)
  • 接收副本的 MOSDPGNotify2 消息

副本

  • 发送 MOSDPGNotify2 消息(通知主副本)
  • 接收主副本的 MOSDPGInfo2MOSDPGLog 消息
  • 根据主副本的信息更新本地状态

8.2 状态一致性保证

  1. 版本控制

    • 使用 eversion_t 管理对象版本
    • 日志条目包含版本信息
    • 通过版本比对确定一致性
  2. 事务提交

    • 状态变更通过事务提交
    • 事务提交后才真正生效
    • 支持回滚机制
  3. 消息顺序

    • 使用 epoch 确保消息顺序
    • 丢弃过期的消息
    • 保证状态转换的原子性

9. 性能优化

9.1 状态转换优化

  • 批量处理:多个状态变更批量提交
  • 延迟激活:某些状态转换延迟执行
  • 资源预留:提前预留恢复/回填资源

9.2 消息缓冲

1
2
3
4
5
6
struct BufferedRecoveryMessages {
std::map<int, std::vector<MessageRef>> message_map;

// 缓冲消息,等待事务提交后发送
void send_osd_message(int target, MessageRef m);
};

优势

  • 减少消息发送次数
  • 保证消息与状态的一致性
  • 提高性能

9.3 状态历史统计

1
2
3
4
5
6
class PGStateHistory {
// 记录每个状态的停留时间
// 用于性能分析和优化
void log_enter(const char *name);
void log_exit(const char *name, utime_t duration);
};

10. 错误处理

10.1 状态机错误

  • Crashed 状态:处理无法恢复的错误
  • 事件丢弃:丢弃无法处理的事件
  • 状态回退:某些错误可能导致状态回退

10.2 超时处理

  • Peering 超时:如果 Peering 长时间未完成,可能触发超时
  • 恢复超时:恢复操作超时处理
  • 消息超时:等待消息超时处理

10.3 异常恢复

  • 状态不一致:检测并修复状态不一致
  • 日志损坏:处理日志损坏情况
  • 数据丢失:处理数据丢失情况

11. 总结

11.1 核心机制

  1. 层次化状态机:使用 boost::statechart 实现
  2. 事件驱动:通过事件触发状态转换
  3. 回调机制:通过 PeeringListener 与上层交互
  4. 事务管理:状态变更通过事务提交
  5. 消息缓冲:优化消息发送

11.2 关键关联

  • PG:通过 PeeringListener 接口关联
  • OSDMap:持有引用,响应 Map 变化
  • PGLog:直接管理,用于 Peering
  • MissingLoc:继承 MappingInfo,定位缺失对象
  • PeeringCtx:管理状态转换上下文
  • OSDService:通过 PG 间接关联

11.3 设计优势

  1. 清晰的状态管理:层次化状态机使状态转换清晰
  2. 解耦设计:通过接口与上层解耦
  3. 可扩展性:易于添加新状态和事件
  4. 可维护性:状态转换逻辑集中管理
  5. 可调试性:状态历史记录便于调试

11.4 相关文件

  • PeeringState.h/cc:状态机实现
  • PGPeeringEvent.h/cc:事件定义
  • PGStateUtils.h/cc:状态工具函数
  • PG.cc:PG 实现 PeeringListener
  • OSD.cc:OSD 触发状态机事件

文章互动

阅读 --

留言

0 条留言

正在加载留言…