采用共享日志实现Raft共识:可行性与利弊分析
Raft改用共享日志的利弊权衡分析
背景与问题
Raft共识协议依赖节点的本地复制日志,现有实现均要求每个节点配备持久化本地存储。在Kubernetes等云原生环境中,无持久化卷的节点可通过普通Deployment轻松部署,而依赖持久化卷则需使用StatefulSet,会引入额外复杂度与限制。
基于此,我提出一种思路:用可追加、可读且能分配单调递增记录ID的公共日志(比如Kafka Topic)替代Raft的本地复制日志,是否可行?这种方案的利弊是什么?
方案流程概述
为说明该方案的运作逻辑,以下是基于Raft的复制键值存储搭配共享日志的流程(括号内为Kafka Topic实现细节):
- 初始领导者选举完全遵循Raft协议
- 当选领导者将客户端的
Put(K,V)事务追加至共享日志(发布到Kafka Topic) - 领导者收到日志写入确认后,记录唯一消息ID(Kafka的偏移量+分区)并同步给所有跟随者;跟随者记录该ID后返回确认
- 当多数跟随者确认收到消息ID后,领导者更新本地内存键值存储,并向客户端返回事务完成确认
- 跟随者异步从共享日志消费新的
Put(K,V)消息,更新自身内存键值存储 - 领导者故障时触发新选举:仅持有最新消息ID的跟随者具备参选资格,确保新领导者数据最新
- 跟随者崩溃重启后,可通过重新消费共享日志的所有记录重构状态(仅需恢复最后处理的消息ID)
读请求处理逻辑
跟随者可响应客户端Get(K)请求:
- 若接受最终一致性:任何已处理领导者同步的最新消息ID对应日志的跟随者均可直接响应
- 若需读己所写一致性:客户端需携带从领导者处获取的消息ID发送给跟随者,跟随者会阻塞直至消费并处理该ID对应的日志消息后再响应
利弊权衡分析
优势
- 简化云原生部署:无需为每个节点配置持久化卷,可直接用
Deployment部署,避免StatefulSet带来的部署复杂度、存储调度限制等问题 - 减少节点本地存储开销:节点无需持久化存储日志,仅需在内存中维护键值存储和最新消息ID,降低存储成本与运维负担
- 日志复用能力:共享日志可被其他系统复用(比如实时数据分析),提升资源利用率
- 简化故障恢复:节点崩溃重启后无需从其他节点同步日志,直接从共享日志重构状态,恢复速度更快
劣势
- 引入共享日志依赖:系统强依赖第三方共享日志组件(如Kafka),其可用性、性能将直接影响整个Raft集群的稳定性。若共享日志故障,整个集群将无法处理写入请求,甚至无法完成领导者选举后的状态恢复
- 性能瓶颈转移:原Raft的日志复制性能瓶颈在节点间网络,现在转移到共享日志的写入吞吐量。若共享日志的写入能力不足,会成为整个系统的性能瓶颈
- 一致性风险:共享日志自身的一致性模型可能与Raft的要求冲突。比如Kafka多分区场景下无法严格保证消息的全局单调递增顺序,而Raft要求日志严格按顺序应用
- 双重确认开销:领导者需要先等待共享日志的写入确认,再等待多数跟随者的消息ID确认,相比原生Raft多了一层开销,可能增加写入延迟
- 选举逻辑复杂度提升:原生Raft通过日志的term和索引判断节点数据新鲜度,该方案依赖共享日志的消息ID,需要额外逻辑保证消息ID的全局唯一性与单调性,选举时的合法性校验逻辑更复杂
- 读一致性额外成本:为实现读己所写一致性,客户端需要存储消息ID并在请求时携带,增加了客户端复杂度;跟随者需要阻塞等待日志同步,也会增加读请求延迟
内容的提问来源于stack exchange,提问作者Igor
相关产品推荐
相关产品推荐

