本节摘要:Cassandra 诞生于 Facebook Inbox Search 的 MySQL 双写困境——2008 年 7 月开源,2010 年进入 Apache 孵化器,2011 年 CQL 成为默认接口。本节对照 Dynamo 论文与 Bigtable 列族模型,说明它为何从第一天起就是「为失败而设计」的 AP 系统。
阅读完本节,你应当能够:
2004 年 Facebook 消息系统已在 MySQL 上吃力:主从断裂、单点故障、写入延迟随规模恶化。2006 年 Inbox Search 更棘手——用户要求数秒内可搜到新消息,团队采用「写 MySQL + 异步推索引」的双写。网络一旦分区,MySQL 成功而索引失败,产品信任直接受损。MongoDB 当时尚未成熟;HBase 强依赖 HDFS 与 ZooKeeper,运维链路过长。Facebook 需要的是:任意节点失效仍服务、写入延迟不随集群线性恶化、读取陈旧度由客户端 CL 决定。
内部设计文档凝练三条信条(SOURCE 1.1):
「系统必须在任意节点失效时持续提供服务。」
「写入延迟不应随集群规模线性增长。」
「读取延迟由客户端可容忍的陈旧度决定,而非服务端强同步。」
2008 年 7 月代码开源;2009 年 Jonathan Ellis 推动 Gossip 升级为带版本向量的反熵同步;2010 年 2 月进入 ASF 孵化器,RFC 流程约束重大特性;2011 年 Cassandra 1.2 弃用 Thrift,CQL 成为默认接口——表面像 SQL,内核强制 PRIMARY KEY 分区,禁止无分区键全表扫描。
| 年份 | 里程碑 | 与竞品对照 |
|---|---|---|
| 2008 | Facebook 开源 | HBase 0.18 仍绑 Hadoop 0.20 |
| 2010 | Apache 孵化 | MongoDB 1.6 副本集 |
| 2011 | CQL 默认 | Mongo 仍 BSON 查询为主 |
| 2015– | 3.x LWT/MV | HBase 强一致读适合离线 MR |
| 2020+ | 4.x 增量 repair、SAI | PostgreSQL 仍是 OLTP 默认 |
2006 年启动的代号「Cassandra」隐喻:系统能预言数据最终状态,分区时却无人保证「此刻谁对」——与 Mongo 主节点仲裁、HBase Master+ZK 形成鲜明对照。
版本选型:生产建议 4.x LTS;4.0 起 Incremental Repair 与 ZDU 显著降低运维窗口。从 2.x 跳跃升级需先读 release note 中 sstable 格式变更。
生态位:Netflix 全球会话、Apple iMessage 后端、Uber 轨迹——共同点是写入 QPS 高、查询路径预定义。若团队期望「像 PostgreSQL 一样 ad-hoc 分析」,应优先考虑 Timescale/ClickHouse,而非硬上 Cassandra。
⚠️ 常见坑:把 Cassandra 当 MySQL 分库分表替代品,却保留 JOIN 思维——上线后第一个
ALLOW FILTERING就是事故前兆。
💡 关键直觉:Cassandra 的历史是「把应用层分布式复杂度下沉到内核」——LWT、MV、TTL 都是这一思路的延续。
下一节在 CAP 三角上精确标注 Cassandra 的默认锚点,以及
QUORUM背后的 W+R≥N 算术。
生产集群不会一直停留在老版本。社区维护的升级路径通常跳不过中间版,每步都有前置条件:
| 起点 | 终点 | 关键前置 |
|---|---|---|
| 2.1.x | 2.2.x | 迁移 cassandra.yaml 参数名 |
| 2.2.x | 3.0.x | 磁盘格式升级(sstables upgrade) |
| 3.0.x | 3.11.x | 滚动升级,逐节点验证 |
| 3.11.x | 4.0.x | 滚动升级,注意 gc_grace_seconds 与 repair 窗口 |
# 升级前快照 + 全量 repair,是任何跨大版本动作的底线 nodetool snapshot -t pre_upgrade_20240814 nodetool repair -full # 滚动升级:一次一个节点,验证 UN 状态后再动下一个 systemctl stop cassandra # 替换安装包后启动 systemctl start cassandra nodetool status
Cassandra 与 DynamoDB 都受 2007 年 Dynamo 论文启发,但演化方向分叉:DynamoDB 走托管化、API 私有化,强一致选项收窄;Cassandra 走开源社区、CQL 标准化,可调 CL 完整保留。若团队已在 AWS,且不想维护集群,DynamoDB 的单分区键查询与 TTL 机制与 Cassandra 的建模直觉高度相似,迁移成本低于从 PostgreSQL 迁移。
用一段伪代码复现 2006 年的问题,理解「发了却搜不到」的根因:
# 伪代码:双写模式在分区下的失效路径 def send_message(msg): mysql.insert(msg) # 主库成功 index.push(msg) # 异步索引,可能失败或延迟 # 若网络分区,用户已发出但搜索索引缺失 → 搜不到
Cassandra 的答案不是消灭分区,而是把两份数据放进同一分区,让主数据与索引副本要么一起可见,要么在修复后一起收敛——这正是第3章「查询驱动建模 + 双表」的源头。
# cassandra.yaml 中与版本演进相关的三个开关 partitioner: org.apache.cassandra.dht.Murmur3Partitioner # 升级时若发现旧集群用 RandomPartitioner,需先规划数据迁移 snapshot_before_compaction: false enable_materialized_views: true
理解这三个开关,就理解了 Cassandra「配置即契约」的版本观:分区器决定数据分布不可轻易变更,快照与物化视图开关则按运维预算权衡。