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. 自测
- CQL 与 SQL 的五处不同?
- 分区键三判据?分区过大怎么处理?
- 宽行与多行分别适合什么查询?
- 为什么说"表是物化视图"?
- 一致性级别怎么选?
答案
- 无 JOIN、主键双层、WHERE 受限、无跨分区事务、一致性可调。
- 高基数、均匀、查询对齐;时间桶或加盐。
- 范围取一段用宽行,按键取单个用多行。
- 按查询建表、写多份,读各取所需。
- 写
QUORUM+ 读QUORUM得强一致;其余按延迟与一致性权衡。
7. 下一篇
S12 系列验收(v3)。
S12-X02 · Cassandra CQL 与分区键选型(附录)
https://www.clxhxhhr.top/posts/5359/ 评论
0 条
还没有评论,先写一条吧。