最近,valkey社区在尝试新的feature,Cluster总线通信方式利用Raft协议,笔者刚学完Raft和主从相关的内容,同时认领了一个issue。 于是想尝试多解决几个这里的问题,就深度研究一下。
以下是几个社区中讨论的链接: 父issue 分为多个subissues:我们总结一下:
1.核心底座:Raft 共识与状态机持久化 #
这是 Raft 算法最原教旨主义的部分,确保集群在断电或崩溃后不丢失状态。
- #3857 状态持久化: 保存当前的任期(Term)、投票给了谁(VotedFor)以及核心的追加日志(Log)。这是节点恢复身份的基石。
- #3858 日志压缩与快照: 随着时间推移,Raft 日志会无限膨胀。必须定期对状态机打快照(Snapshot),并清理旧日志,防止磁盘被打爆。
- #3859 崩溃恢复: 节点重启后,如何通过读取本地日志和向 Leader 拉取缺失日志,平滑地重新加入集群。
2.网络韧性:分区容错与高可用 #
这部分极其考验对底层网络和分布式脑裂(Split-brain)的理解,涉及节点探活和异常状态下的隔离。
- #3860 Pre-Vote 协议: 防止网络分区恢复后,被隔离的少数派节点带着极高的假 Term 强行打断正常 Leader 的任期。
- #3861 少数派分区检测与 Leader 降级: 当 Leader 发现自己被隔离到了少数派网络中,必须主动放弃领导权,停止对外服务。
- #3862 基于复制流的故障检测(去中心化租约): 放弃传统高频的 Ping-Pong 心跳,复用数据同步流来判断节点存活,极大降低网络 I/O 消耗。
3.数据控制面:分片与状态流转 #
这一层将 Valkey 特有的“Slot(槽位)”概念与 Raft 引擎深度绑定,实现数据分片的强一致路由。
- #3863 Shard 级别的 Epoch: 细化版本号控制,用于网络隔离时的请求拦截(Fencing),避免客户端向旧的 Master 写入脏数据。
- #3865 将 MIGRATING/IMPORTING 状态存入日志: 让 Slot 的迁移过程变成具备原子性的共识操作。
- #3874 Leader 侧提案预校验(新引入): 在将操作打包成日志广播前,Leader 先自己校验一下合法性,拒绝不合理的变更,减少无意义的网络浪费。
4.集群拓扑与角色演进 #
打破常规 Raft 的局限,赋予集群更高的扩展性和更灵活的运维手段。
- #3866 非投票成员 (Learner): 只同步数据不参与投票,打破 Raft 节点数量越多性能越差的魔咒。
- #3868 合并非单节点集群: 解决两个已经有独立状态机的集群如何安全“联姻”的问题。
- #3869 同步复制的晋升工作流: 精细化主从切换时的状态机流转。
- #3864 通过 REPLCONF 进行手动故障转移: 保留人工介入强行切换主从的工程后门。
5.全局生态与客户端适配 #
提供“上帝视角”的控制平面,相对来说比较外围一些。
- #3867 CLI 工具链兼容: 修改命令行客户端,剥离与 Raft 异步阻塞相冲突的
MULTI/EXEC事务逻辑。 - #3875 集群级别的 ACL 和 Functions(新引入): 这是一个极其关键的质变。过去配置用户权限(ACL)需要去每个节点单独敲命令;有了 Raft 后,集群终于有了一个全局可靠的元数据中心,只需配置一次,全网自动强一致下发。
社区关于开发动机的讨论 主要是为了解决第一代基于 Gossip 协议的集群架构在超大规模部署、云原生环境以及极端负载下暴露出的底层系统设计缺陷。
1.控制面与数据面的资源争抢 (Resilience & Threading) #
- 单线程瓶颈: 在 V1 架构中,处理集群总线(Cluster Bus)心跳和处理客户端数据读写的逻辑,都挤在同一个主线程(Main Thread)中。
- 假性故障转移 (False Failovers): 当遇到极高并发的客户端读写或者海量的 Pub/Sub 消息时,主线程被长期霸占,导致节点无法及时回复其他节点的健康检查 Ping。这种“控制平面被数据平面饿死”的情况,会引发集群误判节点死亡,从而触发毫无意义的主从切换和集群震荡。
2.拓扑状态缺乏强一致性 (Strong Consistency & Metadata) #
- “最终一致”的局限性: V1 集群依靠 Gossip 协议传播拓扑(谁拥有哪个 Slot,谁是主节点)。但在网络分区等异常情况下,节点的 Epoch(任期版本号)可以在没有多数派共识的情况下被强行修改。这导致拓扑状态不仅不是强一致的,甚至在某些边界条件下连“最终一致”都无法保证,极易引发脑裂和级联故障导致数据丢失。
- 全局配置噩梦: 目前 Valkey 没有一个中心化的元数据存储。如果想要更新 ACL(访问控制)、加载 Functions 或修改全局配置,必须将命令手动分发到集群的每一个节点上,极易产生配置漂移。
3.网络拓扑的数学极限 (Scalability & Gossip Overhead) #
- 网络通信复杂度: Gossip 协议要求集群内的节点两两建立全连接网状拓扑(Full Mesh)并频繁交换状态。随着节点数量增加,集群总线上的冗余通信量呈指数级爆发。
- 500 节点天花板: 这种设计导致 V1 集群的规模上限被死死卡在 500 个节点左右,完全无法满足现代大型业务线动辄上千节点的横向扩展需求。
4.现代基础设施适配度差 (Cloud-Native & Operability) #
- 容器化与动态 IP 不友好: 社区用户指出,在 Kubernetes 等无状态、动态 IP 的临时环境(Ephemeral Environments)中,V1 集群的节点自举(Bootstrap)和替换非常僵化。配置文件中容易堆积失效的 IP 记录,且不同查询命令(如
cluster nodes与cluster shards)返回的节点状态经常自相矛盾。 - 高可用门槛过高: V1 集群的选主只允许 Primary(主节点)投票,这意味着一个具备基础容灾能力的集群至少需要 3 个主节点(形成多数派)。V2 期望引入“参与投票的 Replica(从节点)”,让极小规模的部署(例如单 Shard 架构)也能享受内置的自动故障转移,从而完全吃掉传统 Sentinel(哨兵)模式的应用场景。
- 被动的路由更新: 目前当槽位发生迁移时,客户端往往是通过撞墙(收到
MOVED报错)才去重新拉取路由表。V2 计划借助 RESPV3 协议,主动向客户端推送拓扑变更(Push 机制),大幅降低客户端 SDK 的路由寻址开销。