Cassandra不是关系数据库,它没有JOIN、外键、ACID事务和强一致性,专为高写吞吐、多活容灾与线性扩展设计;其建模必须遵循查询驱动原则,每种查询路径需单独设计宽表并反规范化,主键设计决定数据分布与查询效率。

Cassandra 不是关系数据库,强行当关系库用会踩坑——它没有 JOIN、外键、事务,也不保证强一致性。微服务里选它,图的是写吞吐高、多活容灾、线性扩容,不是为了替代 PostgreSQL。
为什么 gocql 是唯一靠谱的 Go Cassandra 驱动
社区里只有 gocql 维护活跃、支持协议 v4/v5、内置连接池和重试逻辑。其他封装库(比如 cassieq 或自行封装 net/http 调 REST)要么已归档,要么绕过二进制协议丢掉性能和一致性控制。
-
gocql默认启用ConsistencyLevel: Quorum,但微服务读写场景需按需下调:写日志用One,查用户配置用LocalQuorum - 它不自动重连失败节点,得靠
ClusterConfig.Timeout+ConnectTimeout+ 自定义Query.Timeout()控制失败感知边界 - 别开
DisableInitialHostLookup: true—— 在 Kubernetes 中 DNS 变更频繁,关了会导致新 Pod 连不上新增的 seed node
建模必须放弃“一张表一个实体”思维
Cassandra 的查询驱动建模(Query-Driven Modeling)意味着:每个业务查询路径,都得单独设计一张宽表。比如“查某用户最近 10 条订单”,不能靠 JOIN orders + users,而要建 user_orders_by_user_id 表,把用户姓名、订单状态、时间戳全 denormalize 进来。
- 主键分两层:
PRIMARY KEY ((partition_key), clustering_column)—— 第一层决定数据落在哪个节点(必须高基数,避免热点),第二层决定排序和范围扫描能力 - 避免在 WHERE 中用非主键字段过滤,
ALLOW FILTERING在生产环境等于慢查询+OOM - 用
TIMEUUID当 clustering column 比TIMESTAMP更安全:它带节点信息,天然去重且严格单调
gocql.Query 执行时最容易漏掉的三件事
直接 session.Query(...).Exec() 看似简单,但线上常因这几处丢数据或超时:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 没设
Query.Timeout(5 * time.Second)—— 默认无超时,卡住 goroutine 不释放连接 - 没调
Query.Consistency(gocql.LocalQuorum)—— 跨 DC 查询若用Quorum,可能因网络延迟返回Unavailable错误 - 批量写用
Batch时,没控制 size:batch.Size() > 100易触发 coordinator 单点压力,建议按 partition key 分批,每批 ≤ 20 条
横向扩展不是加机器就完事
Cassandra 的“无限扩展”前提是:你的 partition key 设计能均匀打散写入。如果所有写请求都集中在 tenant_id = 'demo' 这个分区,加再多节点也没用——流量全压在 1–2 个 replica 上。
- 用
token()函数验证分布:SELECT token(user_id), user_id FROM users LIMIT 100,观察 token 值是否大致均匀 - K8s 里部署时,别让所有 Cassandra pod 共享同一个 StatefulSet volume claim —— 每个实例必须有独立磁盘,否则 IO 成瓶颈
- 定期跑
nodetool repair -pr(只修本节点负责的 primary range),不然读取 stale 数据的概率随副本数上升而增加
真正难的从来不是连上 Cassandra,而是让业务逻辑适配它的数据模型约束。很多团队卡在“怎么把现有 ORM 映射迁过去”,答案通常是:删掉 ORM,手写 CQL,把查询反推成表结构。

















