本节摘要:Cassandra 用 Gossip 协议在 O(log N) 轮内传播节点状态,Phi accrual 故障检测替代简单心跳超时。Seed 节点仅 bootstrap 新成员,不是 Master。本节对照 HBase 的 ZooKeeper 会话与 Mongo 的 Replica Set 心跳。
阅读完本节,你应当能够:
GossipingPropertyFileSnitch千节点集群若用中心注册表(类似 ZK),ZK 本身成为 CAP 瓶颈。Cassandra 选「流言网络」:每个节点只与少数 peer 交换状态摘要,信息像涟漪扩散。代价是集群视图短暂不一致——新节点加入后,其他节点可能数秒内不知晓,期间路由可能偏旧。HBase 用 ZK 强协调换精确视图;Mongo 副本集 10s 级选举窗口类似「最终一致的控制平面」。
Gossip 轮次:节点随机选 peer,交换 digest;发现版本落后则 pull 增量状态。2009 年 Phantom Protocol 引入版本向量,减少误判宕机。
Phi accrual failure detector:根据心跳间隔分布计算 Φ 值,自适应 GC 停顿——比固定 500ms 超时更适合 JVM 世界。
Token Ring:Murmur3 将 partition key 哈希到 2^63 空间;每个 vnode 占一段 token。Coordinator 本地维护 ring 副本,无独立元数据服务。
| Snitch | 用途 | 对比 |
|---|---|---|
| SimpleSnitch | 单 DC 测试 | 无 rack 感知 |
| GossipingPropertyFileSnitch | 生产多 rack/DC | 读 cassandra-rackdc.properties |
| Ec2Snitch / GceSnitch | 云厂商 AZ 映射 | Mongo Atlas 类似 zone |
Seed 节点:新节点启动时 Gossip 的第一个联系人;建议每 DC 2–3 个固定 seed,但 seed 宕机不影响已 formed 集群——与 HBase Master 不同,seed 不参与写路径仲裁。
防火墙:Gossip 端口(默认 7000/7001)与 storage 端口(7000)需在集群内互通;跨 DC 需控制 Gossip 带宽,有时用 dynamic_snitch 优化读路由。
替换节点:nodetool decommission 让 vnode 平滑迁出;直接 kill 会触发 hint + repair 压力。HBase 需 graceful_stop + Region 迁移脚本。
监控:nodetool gossipinfo 查看 GENERATION/HEARTBEAT;异常 VERSION 差异大提示分区。
⚠️ 常见坑:所有节点指向单一 seed——seed 宕机时新节点无法 join,已运行集群不受影响但扩缩容卡住。
💡 关键直觉:Gossip 是 Cassandra「无主」的控制平面;它的不精确性由 CL 与 repair 在数据平面补偿。
下一节在环上讨论副本如何放置,以及 CL 如何选取法定人数。
# 查看当前节点视角下的全集群状态视图 nodetool gossipinfo # 输出样例(重点看 VERSION 与 HEARTBEAT) # /10.0.1.10 # generation:1723000001 # heartbeat:45213 # status:NORMAL # 发现节点状态异常时,先看这是 Gossip 观点还是真实故障 nodetool status # UN = Up Normal,DN = Down Normal,关键是 UP/DOWN 一致性
如果 nodetool status 里出现 UP 但实际请求超时,多半是网络分区造成视图分裂;此时 CL=LOCAL_QUORUM 的读仍可服务,因为副本按 token 分布在物理上不依赖 Gossip 观点,但修复需要 nodetool repair 收敛版本。
# 1. 新节点配置 seed 指向集群既有节点 # 2. 启动后自动进入 Bootstrap 状态(视图为 BN) nodetool bootstrap # 或直接观察状态变化 # 3. streaming:从 ring 邻居拉取本节点负责的 SSTable nodetool netstats # 观察 Streaming 进度 # 4. 完成后状态变为 UN,开始接收写请求
注意事项:bootstrap 期间不要让新节点立刻承接大流量;stream_throughput_outbound_megabits_per_sec 控制迁出带宽;若 bootstrap 失败,清理该节点的 data 目录重新来过,比手工改 token 更安全。
| 参数 | 建议 | 理由 |
|---|---|---|
gossip_interval_ms |
1000(默认) | 太快耗带宽,太慢拖慢故障发现 |
phi_convict_threshold |
8(默认) | GC 停顿长的集群可调 10–12 |
dynamic_snitch_update_interval_ms |
100 | 读路由避开慢节点 |
gossip_to_phonedix |
true | 记录 Gossip 异常便于排障 |
# cassandra.yaml 片段 phi_convict_threshold: 10 # JVM 偶发长 GC 的集群可放宽判定 dynamic_snitch_badness_threshold: 0.1
对比来看:HBase 把成员状态托管给 ZooKeeper 会话(Session Timeout 判定失联),Mongo 副本集用 10 秒级心跳选举。Cassandra 的 Phi 模型能感知 GC 停顿这种「JVM 特有假死」,这是它作为 JVM 生态成员的自然选择。
# 模拟:集群已 formed,所有 seed 节点停机 # 观察已运行节点的行为 nodetool status # 集群视图仍在,因为 Gossip 已建立互相连接 cqlsh -e "INSERT INTO app.k (k, v) VALUES ('x', 1)" # 写仍然成功
结论:seed 只在「新节点加入」时需要,已形成的集群不再依赖 seed 做任何数据平面操作。这是它与 HBase Master、Mongo 主节点最本质的差异——控制平面的降级不会拖垮数据平面。
-- 新节点加入时若 seed 全不可达会怎样?报错并拒绝 bootstrap -- 因此生产要求每 DC 至少 2 个 seed,且不随节点下线而全部更换
如果设计上把唯一 seed 混在易变节点池里,扩容时就会遇到「新节点进不来」的尴尬。规划 seed 的原则:选择稳定、长期存在、位于集群拓扑中央的节点,并让它们在 yaml 中保持一致列表。
# cassandra.yaml:限制跨数据中心 Gossip 带宽,防止流量计费失控 # 注意该参数只约束 gossip,streaming 用另一个限速 hinted_handoff_throttle_in_kb: 1024 dynamic_snitch_reset_interval_in_ms: 600000
# 查看当前节点对跨 DC 节点的连接状态 nodetool status --resolve-ip # 输出中若出现跨 DC 节点反复 UP/DOWN,优先怀疑带宽或防火墙丢包
跨 DC 场景的 Gossip 有两个运维要点:一是每 DC 各自维护 2–3 个 seed,不要把远端 seed 写进本地 yaml,否则新节点启动会去联系远端;二是用 nodetool gossipinfo 定期核对跨 DC 状态,因为跨 DC 链路是最大不稳定源。与 Mongo 的 replica set 心跳类似,但 Cassandra 的 Gossip 还承担 rack 感知的副本放置语义,信息更重。