Cassandra 的分区键和聚簇键,几张图讲明白

Cassandra 的分区键和聚簇键,几张图讲明白

先交代一下主角。Cassandra 是一个分布式 NoSQL 数据库,最早由 Facebook 开发,用来支撑收件箱这种海量写入的场景,现在是 Apache 顶级项目。它的卖点很直接:数据自动分片到几十上百台机器,写入吞吐量极高,任何一台挂了集群照样跑,加机器就能线性扩容。

你可以把它理解成一个"不怕数据多、不怕机器挂"的数据库。但"不怕"是有前提的——你的数据模型得建对。

Cassandra 查得慢,90% 的锅不在机器,在键。

分区键选错,数据全挤一个节点,热点炸了。聚簇键选错,范围查询变全表扫,毫秒变秒级。两个键加起来不到 20 个字符,决定了你整个数据模型的命运。

但很多人建表的时候,对着 PRIMARY KEY (a, b, c) 发呆:括号里第一个是分区键,后面的是聚簇键——我知道。可为什么要这么分?什么时候该把哪个字段放前面?

这篇文章用四张动图,把底层原理拆开给你看。看完你就知道怎么选了。

先搞清楚一个问题:Cassandra 为什么需要两种键?

传统数据库(MySQL、PostgreSQL)的数据存在一台机器上。查数据就像在图书馆里找书——索引告诉你书架号 + 第几层,一步到位。

Cassandra 不一样。数据分散在几十甚至几百台机器上。你面对的不是一个图书馆,而是一条街上几十家图书馆

这就带来两个问题:

  1. 去哪家? —— 数据存在哪个节点上?
  2. 到了之后怎么找? —— 在那个节点内部,数据按什么顺序排?

分区键解决第一个问题。聚簇键解决第二个。

分区键:数据的「地址」

分区键路由动画

你写入一行数据,Cassandra 拿分区键的值做哈希,算出一个 token,然后把 token 放到一张哈希环上。环上按 token 范围划好了各节点的地盘。token 落在谁的地盘,数据就存谁那儿。

类比:分区键就像快递地址里的区号。同一个区号的所有包裹,都送到同一个分拣中心。

关键性质:同一个分区键的所有行,永远在同一个节点上。 这就是"分区"的含义。

所以选分区键的第一原则:让数据均匀分散。如果 80% 的请求都查 user_id=42,那 42 这个分区就成热点,对应节点 CPU 打满,其他节点闲着。

聚簇键:分区内部的「排序规则」

聚簇键排序动画

数据到了节点之后,同一个分区内可能有很多行。这些行按什么顺序存?答案是:按聚簇键排序,物理相邻存储。

类比:分拣中心收到一堆包裹后,按收件人姓名拼音排好放在架子上。你要找"张"开头的,直接从张那格开始拿,连续拿几格就行,不用翻遍整个架子。

这就是聚簇键的威力:范围查询只读连续的一段,不需要扫整个分区。

选聚簇键的原则:把你最常做范围查询的字段放前面。 比如时间线场景,created_at 做聚簇键,WHERE created_at > '2026-01-01' 就能秒回。

两键组合:一次定位 + 一段连续读

高效查询动画

最好的查询长这样:

SELECT * FROM orders
WHERE user_id = 42
  AND created_at BETWEEN '09:00' AND '10:05';

Cassandra 的执行路径:

  1. 分区键 user_id=42 → 哈希环 → 只去节点 B(A、C 完全不碰)
  2. 节点 B 内,聚簇键 created_at 范围 → 只读连续三行(其余不读)

一次网络跳转 + 一段磁盘顺序读。毫秒级。

这就是 Cassandra 设计的甜蜜点:查询条件和主键结构完美对齐。

反模式:没有分区键 = 挨家挨户敲门

反模式动画

如果你写了这么一条查询:

SELECT * FROM orders
WHERE created_at = '10:05';

注意:WHERE 里没有分区键。

Cassandra 懵了——没有地址,不知道该问谁。怎么办?只能广播:把查询发给集群里的每一个节点,每个节点都扫一遍自己的数据,再把结果交回协调节点合并。

这叫 scatter-gather。节点越多,越慢。10 个节点还行,100 个节点就是灾难。而且很容易超时。

分区键是 Cassandra 的地址。没地址,就只能挨家挨户敲门。

建模心法:三条实操建议

1. 分区键选高基数字段。

user_iddevice_idtenant_id 这种值很多、分布均匀的字段,天然适合做分区键。别用 status(只有几个值)或 country(分布不均)——会热点。

2. 聚簇键按查询模式排序。

你经常 ORDER BY created_at DESC?那 created_at 放聚簇键第一位。经常按 category 过滤?那 category 放前面。聚簇键的顺序 = 你支持的查询模式。

3. 一个分区别太大。

Cassandra 建议单分区不超过 100MB / 10 万行。如果你的分区键粒度太粗(比如用 year 做分区键,一年数据全挤一个分区),就会撑爆。解决办法:加一个"桶"字段,比如 year_month,把大分区拆小。

一张表总结

分区键 (Partition Key) 聚簇键 (Clustering Key)
解决什么 数据去哪个节点 节点内怎么排序
类比 快递地址的区号 分拣中心里的排列规则
选错了会怎样 热点 / 数据倾斜 范围查询变全扫
查询时必须带? 必须(否则全集群扫) 建议带(不带也能查,但可能慢)

写在最后

Cassandra 不是万能的。它的查询模型很"死"——你建表的时候就得想好怎么查,之后很难改。这跟 MySQL 那种"先存了再说,索引后面加"的思路完全相反。

但一旦你把键选对了,Cassandra 在大规模写入 + 按主键查询的场景下,性能是碾压级的。线性扩展、无单点、写入不阻塞读——这些优势的前提,就是你的数据模型和查询模式对齐。

分区键和聚簇键,就是那个对齐的锚点。


如果觉得有用,点个在看,转发给你身边被 Cassandra 慢查询折磨过的朋友。

有什么想法,欢迎在评论区聊聊——每一个留言我都会看。

END