时间序列写入应设 consistency 为 quorum 或 localquorum,避免 localone 导致丢包;timestamp 字段必须用 time.time 类型,不可用 int64 或字符串,否则解析错误。

gocql.Query 的 Consistency 设置影响时间序列写入可靠性
时间序列数据对写入丢包极其敏感,而 gocql 默认使用 LocalOne 一致性级别——这意味着只要本地节点响应就返回成功,哪怕其他副本还没落盘。在高并发写入时,容易出现“写成功但查不到”的现象。
实操建议:
- 写入时间序列(如
INSERT INTO metrics (ts, host, value) VALUES (?, ?, ?))务必显式设为Quorum或LocalQuorum,尤其当集群跨机房部署时 - 避免在
Session.Query()后直接调用.Exec(),应先用.Consistency(gocql.Quorum)链式设置 - 注意:
LocalQuorum比Quorum延迟更低,但要求所有 replica 都在本 DC;若跨 DC 写入,Quorum更稳妥
时间戳字段必须用 time.Time,不能用 int64 或字符串
Cassandra 的 timestamp 类型底层是微秒级 int64,但 gocql 对 Go 类型有强绑定:只有 time.Time 能正确序列化/反序列化。用 int64 传入会导致写入值被截断或解析成错误年份(比如变成 1970 年)。
常见错误现象:
立即学习“go语言免费学习笔记(深入)”;
- 插入后查出来
ts是1970-01-01 00:00:00 +0000 UTC - 按时间范围查询(
WHERE ts > ? AND ts )始终无结果
正确做法:
- Go 结构体字段声明为
TS time.Time `cql:"ts"` - 构造数据时用
time.Now().UTC(),不要自己算毫秒再转time.Unix(0, ms*1e6)(易溢出) - 如果原始数据源只有毫秒时间戳,用
time.Unix(0, ms*1e6)而非time.Unix(ms, 0)
批量写入时间序列要用 gocql.Batch,但别盲目堆数量
单条 INSERT 写时间序列性能差,Batch 能显著提升吞吐,但 Cassandra 对 batch size 极其敏感:超过几百条就可能触发 Request too big 错误或导致 coordinator 过载。
实操建议:
- 单个
gocql.Batch控制在 50–200 条之间,按host或metric_name分组后再 batch,避免跨 partition 批量(Cassandra 不支持跨 partition atomic batch) - 禁用
UNLOGGEDbatch——时间序列通常不允许丢失,LOGGED是默认且必须的 - 不要用
session.Batch()创建后反复复用;每次写新 batch 都要新建&gocql.Batch{Type: gocql.LoggedBatch}
按时间范围查询时,WHERE 条件必须包含分区键,否则报 Cannot execute this query as it might involve data filtering
时间序列表通常按天/小时建分区(如 PARTITION KEY (host, day)),查询 WHERE ts > '2024-01-01' AND ts 会失败,因为 <code>ts 是 clustering key,不是分区键。
正确姿势:
- 查询前先算出目标分区键值,例如把
2024-01-01T10:00:00Z格式化为"2024-01-01",然后写WHERE host = ? AND day = ? AND ts > ? AND ts - 如果业务需要灵活时间范围且无法预知分区,考虑用物化视图(不推荐)或改用
TimeWindowCompactionStrategy+ 宽表设计,让分区粒度更粗(如按月) - 永远不要在生产环境开启
ALLOW FILTERING——它会全表扫描,查一分钟数据可能拖垮整个节点
时间序列场景下,分区键设计和查询路径绑定极紧,漏掉一个 AND day = ? 就不是慢的问题,而是根本跑不起来。










