ClickHouse 很适合做日志、埋点和统计分析,但它不是把 MySQL 写法搬过去就能跑好的数据库。统计链路通常要同时考虑消息拆分、批量写入、大字段处理和失败兜底。
这篇整理一个通用的 ClickHouse 统计链路设计思路。
链路可以分成四段
一个常见统计链路可以拆成:
- 业务服务产生事件。
- 事件写入 MQ。
- 消费端批量处理消息。
- 数据落到 ClickHouse 或外部对象存储。
拆开之后,每一段都有自己的关注点。生产者关注事件格式和 topic;消费者关注批量、幂等和失败处理;ClickHouse 关注表结构、写入频率和查询模式。
Topic 拆分要围绕业务维度
如果所有事件都挤在一个 topic 里,后续消费逻辑会越来越重。按业务类型拆 topic 的好处是:
- 消费逻辑更清晰。
- 不同业务可以独立扩容。
- 故障影响范围更小。
- 后续做限流、重试和告警更方便。
但 topic 不是越多越好。拆分之前要确认业务边界、消费方数量、配置维护成本和监控方式。
批量写入是 ClickHouse 的关键
ClickHouse 更喜欢批量写入,而不是高频单条插入。消费端可以按数量或时间窗口攒批:
- 每 N 条写一次。
- 每隔几秒写一次。
- 达到数据大小阈值写一次。
批量写入能减少连接和提交开销,也更符合 ClickHouse 的存储模型。需要注意的是,批量失败时要有清晰的重试或兜底日志,不然数据丢失很难补。
大字段可以外置到对象存储
统计事件里经常混入大字段,例如输入文本、输出文本、代码片段、文件内容或长响应体。它们直接写入 ClickHouse 会带来几个问题:
- 单行数据过大。
- 写入成本上升。
- 查询时不一定需要读取。
- 表结构和压缩效果变差。
更稳的做法是把大字段上传到对象存储,只在 ClickHouse 中保存引用路径、摘要、大小和必要的元数据。这样既保留追溯能力,也能让统计表更轻。
失败兜底要单独设计
统计链路不可能只靠“异常抛出去”解决问题。至少要保留:
- 消费失败日志。
- 原始 payload 摘要。
- 批量写入失败的错误原因。
- 对象存储上传失败时的降级策略。
- 可重放或可人工补偿的线索。
如果链路里有 MQ 重试和死信队列,也要提前确认版本、配置和平台能力,避免上线后才发现不可用。
上线前要验证什么
上线前建议检查:
- 老 topic 和新 topic 的兼容路径。
- 开关关闭时是否仍走旧链路。
- 新 topic 消费日志是否清楚。
- ClickHouse 是否能查到新数据。
- 大字段外置后是否能反查。
- 批量写入失败是否有兜底记录。
- 回滚后消费者是否停止处理新链路。
ClickHouse 统计链路的难点不在单个 SQL,而在数据从业务进入分析库的整个过程。把 MQ、批量、大字段和兜底先想清楚,后续排查会省很多时间。




