1286 字
约 4 分钟
8
S12-X02 · Cassandra CQL 与分区键选型(附录)

适用读者:要从 MySQL 迁到 Cassandra、或要判断"这张表能不能放进 Cassandra"的人。
前置:S12-B02(Redis 数据结构与编码)、S12-A03(Key 设计与容量估算)、S17-B02(分布式存储)。
覆盖旧文:2945(CQL 基础入门:像操作 MySQL 一样使用 Cassandra,6,843 字符)、4587(Cassandra 分区键:是什么、有什么作用、如何选型,3,203 字符)。
扩展点:E-S12-021(CQL 与 SQL 的五处不同)、E-S12-022(分区键三判据与"宽行 vs 多行"取舍)。
下一篇:S12 系列验收(v3)。


1. 一句话结论

Cassandra 不是"没有 JOIN 的 MySQL",它是一张按分区键切好的分布式有序 Map。CQL 长得像 SQL,但每一列设计都要先回答"查询怎么查",再倒推表结构——这是它与关系库最根本的分歧。

出处:A-2945、A-4587。


2. CQL 与 SQL 的五处不同(E-S12-021)

# 差异 说明
1 无 JOIN 需要冗余写(反范式),一张表服务一个查询
2 主键 = 分区键 + 聚类列 分区键决定落在哪个节点,聚类列决定分区内排序
3 WHERE 受限 只能按主键(或建了索引的列)过滤;ALLOW FILTERING 是危险信号
4 无跨分区事务 轻量事务(LWT)只在单分区内;批量(BATCH)不保证原子跨分区
5 最终一致可调 ONE/QUORUM/ALL 按读写路径选,QUORUM + QUORUM 才强一致
-- 环境:Cassandra 4.x,cqlsh
CREATE KEYSPACE IF NOT EXISTS blog
  WITH replication = {'class':'NetworkTopologyStrategy','dc1':3};

CREATE TABLE IF NOT EXISTS blog.posts_by_user (
  user_id   uuid,
  created_at timestamp,
  post_id   uuid,
  title     text,
  PRIMARY KEY ((user_id), created_at, post_id)   -- 分区键 user_id;聚类列 created_at, post_id
) WITH CLUSTERING ORDER BY (created_at DESC);

INSERT INTO blog.posts_by_user (user_id, created_at, post_id, title)
VALUES (11111111-1111-1111-1111-111111111111, toTimestamp(now()), uuid(), '第一篇');

SELECT * FROM blog.posts_by_user
WHERE user_id = 11111111-1111-1111-1111-111111111111 LIMIT 20;
-- 预期:按 created_at 倒序返回,无需 ORDER BY(顺序由表定义决定)

判据:"能在 WHERE 里只写分区键 + 聚类列,就说明这张表设计对了"——需要 ALLOW FILTERING 时,基本等于表建错了。


3. 分区键三判据(E-S12-022)

① 高基数:分区键取值要足够多,避免热点(用 user_id 而非 status)
② 均匀:数据量与访问量在节点间均匀(避免"大 V 分区")
③ 查询对齐:主要查询必须能带上分区键(否则全集群扫描)
反模式 后果 处置
用低基数列做分区键(如 type) 单分区膨胀、热点节点 换高基数列,或加时间桶
分区超过 ~100 MB / 10 万行 读放大、修复慢 时间桶:((user_id, yyyy_mm), created_at)
大 V 单分区 单节点过热 加盐/分桶(bucket = hash(id) % N)
想"一表多查" 只能 ALLOW FILTERING 按查询建表(写多份)

判据:"Cassandra 的表是物化视图,不是实体表"——同一个实体按不同查询建多张表,写入时同步写,读时各取所需。

宽行 vs 多行:

宽行(分区内很多聚类行):适合"取最近 N 条"(时间线、消息)
多行(多个小分区):适合"按 id 精确取"(用户、设备)
判据:查询是"按范围取一段" → 宽行;"按键取单个" → 多行

4. 与 Redis / MySQL 的分工

需求 选型
强事务、复杂查询、报表 MySQL
单键高频读写、缓存 Redis
海量写入、按分区键范围读、多地域 Cassandra
全文检索 ES(S13)

判据:"Cassandra 的强项是写入吞吐与线性扩展,不是查询灵活度"——需要灵活查询时,用 ES 做二级索引(S13-A01 的同步思路)。


5. 反例:六种"迁移就崩"

做法 后果
直接照搬 MySQL 表结构 查询全部要 ALLOW FILTERING
用自增 ID 做主键 热点分区(写入全打一个节点)
分区无上限增长 单分区过大,读超时
依赖跨分区事务 数据不一致
一致性级别全用 ONE 读到旧值,业务以为是 bug
用 IN 查多个分区键 协调节点扇出,延迟抖动

6. 自测

  1. CQL 与 SQL 的五处不同?
  2. 分区键三判据?分区过大怎么处理?
  3. 宽行与多行分别适合什么查询?
  4. 为什么说"表是物化视图"?
  5. 一致性级别怎么选?
答案
  1. 无 JOIN、主键双层、WHERE 受限、无跨分区事务、一致性可调。
  2. 高基数、均匀、查询对齐;时间桶或加盐。
  3. 范围取一段用宽行,按键取单个用多行。
  4. 按查询建表、写多份,读各取所需。
  5. 写 QUORUM + 读 QUORUM 得强一致;其余按延迟与一致性权衡。

7. 下一篇

S12 系列验收(v3)。

S12-X02 · Cassandra CQL 与分区键选型(附录)
https://www.clxhxhhr.top/posts/5359/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。