本节摘要:Cassandra 的三大工程标签——去中心化(无主 P2P)、线性可扩展写入、原生多数据中心——直接来自 Dynamo 设计。本节用对照表说明 Mongo 副本集与 HBase Master 在这些维度上的不同代价。
阅读完本节,你应当能够:
NetworkTopologyStrategy 跨 Rack/DC 副本放置MySQL 主从扩容到瓶颈后,常见方案是分库分表——应用层承担路由、跨片事务消失。MongoDB 分片集群有 Config Server + mongos,仍有多组件协调。HBase 扩 Region 要 ZK 与 Master 参与。Cassandra 的承诺是:加一台机器,整集群写吞吐近似 +1 台的能力(在分区键设计合理前提下)。代价?没有中心控制台帮你「一键平衡」,你得理解 Token、vnode、repair。
每个节点同时是:数据副本持有者、请求 Coordinator、Gossip 参与者。没有专用 Master;nodetool status 看到的 UN(Up Normal)状态来自 Gossip 最终一致视图。对比:
| 维度 | Cassandra | MongoDB | HBase |
|---|---|---|---|
| 协调 | Gossip | Primary 选举 | Master + ZK |
| 元数据 | 环上 Token | Config Server | META 表 |
| 脑裂 | CL 降级 | 需 majority | ZK fencing |
Partition Key 经 Murmur3 哈希落 Token Ring;vnodes(默认 256/token/节点)把物理节点映射为环上多段,避免旧版「一节点一环」在扩缩容时大规模迁移。写入路径:CommitLog → MemTable → SSTable(详见 2.3)。Mongo 分片靠 chunk 迁移;HBase 靠 Region split——二者都有「热点分片」风险,Cassandra 靠建模拆 partition key。
CREATE KEYSPACE global_app WITH replication = { 'class': 'NetworkTopologyStrategy', 'dc-east': 3, 'dc-west': 2 };
配合 GossipingPropertyFileSnitch 与 cassandra-rackdc.properties(dc= / rack=),副本优先跨 Rack、跨 DC。MongoDB Global Cluster 是较后产品;HBase 跨 DC 复制通常走异步 Replication,运维更重。
热点分区:即使用 vnode,单个 partition key 仍落同一 replica 集——用户 ID 作 key 的「大 V 用户」会把写压到 3 台机器。解法:复合 partition key 或写前加盐(牺牲范围查询)。
多 DC 读:客户端驱动应配置 DCAwareRoundRobinPolicy,默认连本地 DC,避免跨洋 QUORUM 读。
何时不必 Cassandra:数据量 < 单机 PostgreSQL 舒适区、查询模式频繁变更、团队无 7×24 repair 轮值——Mongo 或 PG 更省总拥有成本。
⚠️ 常见坑:以为「多 DC 复制」等于「多活自动冲突解决」——业务仍需 LWW 或应用层合并策略。
💡 关键直觉:三大特性是同一枚硬币——去中心换运维透明,线性写换建模约束,多 DC 换 CL 与 repair 纪律。
第2章进入 Gossip 与 Token Ring 的实现,以及 LSM 读写路径如何支撑上述特性。
# 查看每个节点的 token 段数、负载与状态(UN=Up Normal) nodetool status # 输出中 Load 列的偏差是判断数据是否均匀的第一眼指标 # 查看环上每个 token range 的主副本归属 nodetool ring # 确认 Gossip 与网络分区视图是否一致 nodetool gossipinfo
如果某节点 Load 明显高于均值,先怀疑分区键设计(单一热点 key),再怀疑 vnode 数量配置不当(如手动改成 num_tokens=1)。
热点出现时按「先诊断、再改造、后验证」三步走:
-- 用 token() 函数定位大分区 SELECT token(user_id), user_id, count(*) AS event_cnt FROM user_events WHERE user_id IN ('vip-001', 'vip-002') -- 仅诊断用,勿上生产
| 手段 | 代价 | 适用 |
|---|---|---|
| 复合 partition key 加盐 | 查询需 fan-out | 单一热点 key |
| 时间桶拆分(如按天分区) | 跨天查询需并查 | 时序数据 |
| 拆为多行(分区内聚合) | 写放大 | 计数器、热度表 |
# 加盐示例:把热门 user_id 拆到 16 个桶 def partition_key(user_id: str, salt: int) -> str: bucket = zlib.crc32(user_id.encode()) % salt return f"{bucket}:{user_id}"
上线前逐项核对,缺一项都可能让 NTS 形同虚设:
cassandra-rackdc.properties 声明了正确的 dc= 与 rack=cassandra.yaml 的 endpoint_snitch 与 rackdc 文件配套(GossipingPropertyFileSnitch)NetworkTopologyStrategy 而非 SimpleStrategyDCAwareRoundRobinPolicy 固定本地 DCnodetool describecluster 确认各 DC 的 RF 生效# 验收样例:跨两 DC 的复制策略 CREATE KEYSPACE shop WITH replication = { 'class': 'NetworkTopologyStrategy', 'dc-east': 3, 'dc-west': 2 };
| 动作 | Cassandra 预期 | 实际代价 |
|---|---|---|
| 加 1 节点 | 写吞吐 +N 份 | streaming 占带宽,需限速 |
| 减 1 节点 | 平滑 decommission | 数据迁移期间 I/O 峰值 |
| 多 DC 扩一区 | 本地读变快 | repair 范围扩大、跨 DC 带宽 |
| 均匀扩容 | token 分布更细 | Gossip 负载上升(可忽略) |
# 加节点前后对比写延迟,验证「线性扩展」承诺 nodetool tpstats | grep -i "Write" # 若 WriteLatency 上升,检查是否出现流式迁移与写路径争抢
MongoDB 分片集群加 shard 后存在 chunk 均衡窗口,HBase 加 RegionServer 后触发 Region 重分布,二者同样有「加完机器反而更慢一段时间」的过渡期。Cassandra 的差异在于:vnode 让均衡粒度更细,通常分钟级内恢复稳态。这个「过渡期有界、可预期」是分布式系统成熟度的重要标志。
-- 无中心写入:任意节点都可当协调者 INSERT INTO orders (order_id, user_id, amount, ts) VALUES ('ord-8842', 'u-7788', 199.00, toTimestamp(now()));
# 观察这次写入实际上落在哪个节点、哪些副本 nodetool getendpoints shop orders ord-8842 # 输出该分区的全部副本端点,验证 NTS 跨 rack 放置
这一步把三大特性串成闭环:去中心化(任意节点接请求)→ 线性扩展(hash 均匀分散到 vnode)→ 多 DC(NTS 决定副本落在 dc-east/dc-west)。任何一环配置错,都会在 getendpoints 的结果里暴露——这也是运维排障时第一个要看的输出。