线性一致读
raftpp 通过 ReadIndex 路径提供线性一致读支持,不直接返回业务数据,而是为业务层建立安全读取的时刻。
两种模式定义在 include/raftpp/core/read_only.h:
SafeLeaseBased
通过法定多数确认读许可,更保守,适合默认使用。
LeaseBased
Section titled “LeaseBased”基于 leader lease 判定读许可,延迟更低,前提更严格。
LeaseBased 依赖 check_quorum = true,不满足则无法正确建立 lease 读语义。
ReadIndex() 的语义
Section titled “ReadIndex() 的语义”Raftor::ReadIndex() 成功回调表示 RAFT 层已确认读索引,且本地状态机应用进度已达到该索引。
ReadyProcessor 仅在 applied_index >= read_state.index 时才调用 CompleteRead()。
不直接返回业务数据的原因
Section titled “不直接返回业务数据的原因”ReadIndex() 建立一致性边界,不代替状态机读取业务数据。实际读取发生在:
ReadIndex()回调成功之后。- 应用层从状态机或业务存储读取所需值。
在 Raftor 中的处理路径
Section titled “在 Raftor 中的处理路径”Raftor 中只读请求的处理步骤:
- 业务线程调用
ReadIndex()。 - 请求进入线程安全的
ReadIndexQueue。 - 事件循环线程调用
ProposalTracker::TrackRead()跟踪该请求。 - 事件循环线程调用
raw_node_->ReadIndex(ctx)向 RAFT 层发起读索引请求。 - 当
Ready.read_states返回读索引结果后,ReadyProcessor把它们加入pending_reads_。 - 当本地
applied_index达到对应索引时,触发回调成功。
领导权变化的影响
Section titled “领导权变化的影响”ReadyProcessor 检测到节点失去领导权时:
- 将所有挂起提案以
ProposalDropped结束。 - 将所有挂起读请求以
LostLeadership结束。
客户端须将 LostLeadership 视为正常控制流。
raftor->ReadIndex("ctx", [](raftpp::Result<void> result) { if (!result) { return; }
// 在这里读取业务状态});- 无明确延迟优化需求时优先使用
ReadOnlyOption::Safe。 - 如果使用
LeaseBased,必须同时启用check_quorum。 read_index_timeout与部署环境的网络和调度延迟相匹配。