目录
原文整体框架
架构:副本、分片与负载均衡
存储:存算分离的现实与妥协
升级:从 3 小时到 CI/CD 全自动
配置与测试
成本与人
写入:全文精华
读负载与查询设计
回填:MV 唯一正确姿势
监控与日常运维
杂项但致命
一页纸行动清单
ClickHouse 没有优化器,你就是优化器 ; ClickHouse 没有护栏,你就是护栏 。
SECTION 01
原文整体框架
作者从 18.4 版本开始运维 ClickHouse 近 6 年,管理多个 PB 级集群,还给上游提交过备份引擎、JOIN 性能优化、分布式 JOIN 等关键代码。文章立场鲜明:不讲优点,专讲问题。
章节 核心命题
Architecture 副本+分片模型;负载均衡器是核心;写副本与读副本分离(compute-compute separation)
Storage 开源版云存储支持薄弱;zero-copy 复制可用但有数据丢失风险;压缩用 ZSTD(1)
Upgrades 利用复制协议向后兼容做滚动升级;四步验证体系;把升级做成 CI/CD
Config & Testing 跟踪 settings 变更;必须读源码;测试要跑真集群(≥2 节点 + Keeper)
Costs 成本公式拆解;32 核 ≈ 5GB/s 的经验法则;人力配置建议
Ingestion 全文最重章节:parts/merges 平衡艺术;背压;防重复、防 OOM、防 too many parts
Part II 负载隔离、查询四规则、MV 回填 Null 表法、system 表监控、副本下线多步流程
SECTION 02
架构:副本、分片与负载均衡
App
BI 工具 ×2
cli / 分析师
写入管道
负载均衡器
负载 / 缓存亲和
一致性哈希路由
写副本(专用)
compute-compute 分离
写流量直达
读副本 A(实时)
读副本 B(实时)
读副本 C(长查询)
Keeper ×3
独立机器部署
复制协调 / DDL 队列
ZK 病 = 全集群病
作者推荐的集群拓扑:LB 感知后端状态做智能路由;写副本隔离并配 failover;Keeper 独立部署;读副本按负载类型分组。
实战路径
起步不分片,只加副本 :垂直扩容扛大查询,加副本扛流量。分片最大的坑是 re-sharding 极其痛苦 ,靠聪明的 schema 设计可以长期推迟。
前置带业务逻辑的 HTTP LB :按负载、副本类型、一致性哈希(利用缓存命中)路由。基础部署不必这么复杂,但写副本隔离建议第一天就做。
按工作负载隔离副本 :有 p99 要求的查询单独隔离一组副本,负载压在 40% 以下 ,高百分位延迟才稳。实时亚秒查询是昂贵的,别幻想 spot 实例。
成本放大的算术题
300TB 的表扛 1000 QPS,单副本扛 100 QPS → 需 10 副本 → 3000TB 存储 。用 SSD 的话账单会教你做人——这是作者倾向存算分离的根本动机。
用户 solatic 质疑作者用 HTTP 而非原生 TCP:低延迟是 ClickHouse 核心目标,持久 TCP 免握手更契合。前 Tinybird 员工 eclbg 澄清:他们用 HTTP keep-alive 长连接,开销问题已解决 。
选哪个协议不是关键,连接复用 才是。HTTP 的生态(LB、探针、限流、标准超时语义)对运维更友好。
SECTION 03
存储:存算分离的现实与妥协
热/冷分层:热数据驻留本地 SSD 保延迟,冷数据下沉 S3 控成本
存储形态 机制 风险
本地磁盘 副本间互拷(Keeper 协调) 成本高,扩缩容不灵活
S3 各存一份 每副本独立写 S3 写操作费爆炸(CH 为本地盘设计,文件多、写频繁)
zero-copy 复制 副本共享 S3 同一批 part 官方明确不支持生产
zero-copy 的真相(扩展核实)
Zero-copy replication is a poorly designed feature; it barely works. We don't expect it will be ready for production usage. It will be left in an experimental stage for a long time, maybe several years.—— ClickHouse 创始人 Alexey Milovidov,GitHub issue #49383,2023-05
2026 年的 HN 讨论证实这一态势延续至今:社区认为官方在开源版刻意"看门" zero-copy,因为它是 ClickHouse Cloud 商业模式的核心;也有人为之辩护——这正是"别人出钱让你免费用其余全部功能"的合理对价。
作者的分层建议
想用存算分离 → 用 zero-copy,但盯紧 part 操作 (会丢数据、在 S3 留垃圾);Tinybird 用私有 fork 的改良版。
不够勇敢 → 热/冷分层 或纯 SSD,然后盯死成本。配套:本地 SSD 做 S3 缓存,按用量调大小。
压缩默认 ZSTD(1) ,可按列设置;定期重测写速/读速/压缩比——你的数据可能适配别的算法。
solatic 的反向观点值得认真回答:ClickHouse 的低延迟优势恰恰来自 NVMe 本地盘。如果数据都要放对象存储、接受多跳网络延迟,为什么不直接用 Snowflake 这类天生存算分离的 OLAP?——这是选型层面必须先想清楚的问题。
SECTION 04
升级:从 3 小时战战兢兢到 CI/CD 全自动
作者团队第一次升级:2 周准备 + 3 小时操作。四年后做到无停机、无性能降级、纳入 CI/CD——"据我所知没有第二家公司做到"。前提是复制协议向后兼容 。
滚动升级 SOP(可直接照抄)
用新版本加一个副本 进集群
盯日志——ClickHouse 爱打看似 critical 实则无害的日志,头几次会吓出心脏病
升级期间避免 DDL (加列、跳数索引等结构变更)
全集群升完前,不用新版本任何新特性
先导一部分读 流量,看延迟 / 内存 / 资源
再测写
切真实流量;不放心就观察几小时
逐个升级其余副本
你会遇到的四类问题
问题 频率 对策
存储格式不兼容 2 年 2-3 次(多租户全数据类型才易撞上) 发布后至少等 1 个月再升 ;出事就钻文件系统或恢复备份
SQL 行为变化 常见(多由 bugfix 引起) 用 system.query_log 回放真实查询做回归
性能回退 偶发 升级前跑性能基准,备好回滚
Settings 变更 每次都有 版本间 settings diff 自动化;CI 指向 master 构建
验证体系(进阶目标)
CI 跑多版本混部集群 测试,验证不同版本可共存;
每天用下一版本回放全部真实查询 ,出问题就修或通知用户;
全部通过 → 自动升级。
升级能力靠肌肉记忆 —— through repetition, suffering, and recovery.—— 原文
SECTION 05
配置与测试
⚙
跟踪 settings 变更 在源码里盯默认值与 flag 翻转,做自动化 diff。changelog 是入口,但自己的 diff 系统才可靠。
📖
必须读源码 作者管过几百个 Postgres 集群都不需要读源码,ClickHouse 不行。头部用户几乎都有上游 patch。
3
CI 三版本策略 生产版本 + master + 目标升级版本,全量跑你的分析查询。Because you are testing your analytics queries, right?
☒
绝不测单实例 至少 2 节点 + Keeper。单实例测不出建表失败、复制延迟等集群特有问题。
SECTION 06
成本与人
成本清单 = 副本机器费 + ≥3 个独立部署的 Keeper 节点 + 存储(本地盘不能缩容;S3 要算操作费)+ HA 负载均衡器一对 + 备份存储。
Keeper 必须独立部署:与 DB 同机时机器过载 → Keeper 变慢 → 表进入只读(最好情况)。原文:"A ZK problem means you are fucked."
经验法则
32 核机器健康吞吐 ≈ 5GB/s (未压缩数据);单机扫描约 500MB/s。
遵守基本规范 vs 不遵守,所需硬件差 3-4 倍 ——专人看集群是省钱的。
人力:小集群 1 人兼职;>20k 行/s 写入且多人推变更 → 1 个全职,还要管"人们写出的疯狂查询"。
针对"需要全职盯查询",zbentley 指出这其实是旧时代 DBA 文化的价值——不是写查询,而是做查询与 schema 的守门人/限流器 。cogman10 给出平衡方案:DBA 不做 gatekeeper 做 guardian ——DB 出问题的第一道防线,简单问题直接修,复杂问题与开发结对,查询仍由开发写但有专家兜底。
不必复刻专职 DBA,但必须有人对查询质量和表设计有否决权——否则 ClickHouse 会以 OOM 的方式行使否决权。
SECTION 07 · 全文精华
写入(Ingestion)
Every single company handling ClickHouse struggles with ingestion. They lose data (most of the time without knowing it), duplicate data, take the database down…—— 原文。HN 上 PostHog 前员工 yakkomajuri:"读到 too many parts 我 PTSD 都犯了";同事 fuziontech:"Slack 上天天都是 CH 需要更多磁盘来追 merge。"
insert → 小 part → 后台 merge → 大 part:读要快就要少而大的 part,但大 part 的 merge 吃 CPU/内存/时间
写入是五件事的平衡艺术:merges、inserts、reads、mutations、表设计 。
典型事故链
大查询吃光 CPU/IO
insert 堆积
内存上涨
OOM
丢数据(且不自知)
ClickHouse 运维的标准事故链——每一环都有监控点可切断
可操作清单
攒批 insert ,每次目标只产生 1 个 part ;按分区攒批、不同分区不同 flush 节奏(别每秒刷新上月分区)。
只有真正需要的表才高频写。
用 S3 务必开 Compact parts ——省大量写操作费,避免撞 S3 限流;不用 S3 也建议开。
配一块"小热盘":写入和首轮 merge 在本地盘完成再下沉 S3,省大量操作费。
调 max part size 减少多余 merge,但别让 part 过大。
分区键设计教育 :一天一分区却一次灌 3 年数据 = 一次 insert 产生上千 part = too many parts。
MV 要管控 :MV 在 insert 时执行,每个都拖慢写入;写得差的 MV 直接 OOM 服务器(Tinybird 有自动熔断系统)。
merge 追不上 insert → 加大 merge 线程池 / 写入背压 / 调大队列上限。
背压与防重复
生产必须有背压队列 ,否则任何小事故都演变成丢数据。Kafka 常见但贵(Tinybird 因多租户 + 按表调优需求自研)。突发流量峰到来时来不及扩容,队列是唯一缓冲。
重复数据 :insert 失败重试而系统没设计好 → 数据重复 → 所有 MV 和统计全错。幂等性必须在应用层设计 。
solatic:列存数据库的本质权衡就是"写入慢/异步换查询快",Kafka 缓冲天然契合;若业务要求写入立即可见,那是选型问题而非运维问题。背压不是补丁,是架构的固有部分。
SECTION 08
读负载与查询设计
If you see any benchmark that only gives read performance, it may look nice in the benchmark, but that's not true in real life.—— 原文:读的快慢取决于 part 数量,part 数量取决于写入。纯读 benchmark 都是骗人的。
四类流量与隔离
实时查询(喂 dashboard)/ 长查询(临时分析)/ 回填 / 其他非实时。核心矛盾:长查询不能拖垮实时查询的 p95+ 。方案:按负载分副本(贵)、应用层 + LB 智能路由(Tinybird:感知副本状态选路,必要时直接拒绝查询保服务器 )、spot 副本跑长查询。查询入口至少 4 个:app、cli、BI、以及 BI(故意的——BI 生成的查询烂到要数两遍)。
关键 settings
参数 建议
max_threads实时查询设 1 ;高 QPS 下 >2 会吃掉大量硬件。瓶颈通常是扫描速度
max_memory大 GROUP BY / JOIN / 窗口函数要给高
max_bytes_before_external_group_by要速度就给高,避免中间结果落盘毁性能
max_concurrent_queries千万别关 ——服务器过载时的救命稻草
查询设计四规则(背下来就是 p95 用户)
① sorting key 列过滤 烂设计 = 慢 10-100 倍
② PREWHERE 小列 高选择性 · 非 String/Array
③ IN 等排除操作 把数据滤出去
④ JOIN / GROUP BY 重操作永远放最后
作者提示:把这四条规则 + 表 schema 喂给任意 LLM,它就能写出不错的查询
OOM 后重启加载可能要几分钟——HA 设计必须把这个恢复时间算进去。
SECTION 09
回填:MV 回填的唯一正确姿势
场景:表在持续写入,表上有 MV,你加了一个新 MV 要回填历史数据。
❌ 不要用 POPULATE :官方文档明确不推荐——建 MV 期间写入的数据不会进入 MV。
❌ 不要裸跑 INSERT INTO ... SELECT *:可能丢/重数据,还吃爆内存。
✅ 正确做法:在真实表前挂一张 Null 表,调大每 block 推送行数 (避免产生几千个 part),经 Null 表链路灌入。
历史数据 SELECT 大 block 批量
Null 表 不存数据 · 只触发 MV
新物化视图 与在线写入同一条链路
目标表 不丢不重
Null 表回填法:回填数据与在线写入走同一条 MV 链路,天然规避不一致
SECTION 10
监控与日常运维
必监控指标(常规 CPU/内存/IO 之外)
指标 为什么
运行中查询数 负载基线
Keeper 延迟 Keeper 病则全集群病
S3 错误 用了就要盯
复制延迟 加副本、追数据时关键
DDL 队列长度 卡住会阻塞全集群 DDL
Merge 队列 暴涨 = 写入/merge 失衡前兆
Merge 内存 / Mutations OOM 预警;容易卡死且 kill 不总是有效
关键错误告警:表只读 ("撞到这个基本就完蛋了")、Keeper 错误、max_simultaneous_queries 触顶、segfault (必须定位到具体查询,否则集群被同一条查询反复打挂,你一直 on-call)。
system 表:救火时的圣经
system.query_log —— 你的圣经。ProfileEvents 列告诉你查询到底干了什么,背熟列名;
system.processes —— 着火时看正在跑什么;
system.part_log —— part 的合并与流转;
system.tables / system.columns —— 表结构。
副本下线多步流程 & ON CLUSTER 陷阱
正确顺序:先摘流量 → 等写入和查询完成 → 必要时 kill → 再关机 。有副本宕机时 ON CLUSTER 操作会拖很久,应用超时没设好会连环出错——"trust me, they're not"。超低延迟场景(<20ms)要预热缓存 ,盯 mark_cache 内存。
SECTION 11
杂项但致命
🛡
删表保护 默认 >50GB 的表禁止 DROP——别手贱调低 。世界上只有两种数据工程师:误删过表的,和将要误删的。
⚡
MV 是杀手级特性也是杀手 难管理、内存炸弹、产生大量 part,每个新 MV 都拖慢写入。
☠
高危列类型 高基数列(>2 亿)上的 uniqExactState,merge 时能杀掉集群。聚合状态列都要小心。
128
index_granularity ≥ 128 低值只对点查有用,否则会杀掉服务器。
选型横向定位(来自 HN a34729t)
Trino :联邦查询引擎,无二级索引,典型场景是查数据湖(Iceberg/Parquet);
ClickHouse / Pinot / StarRocks / Druid :真正的 OLAP 数据仓库,差异在写入速率与索引能力,CH 与 Pinot 最接近;
关键约束:二级索引与查询引擎强耦合 ——别幻想 A 引擎写索引、B 引擎来查;
hodgesrm(Altinity):日志/Web 分析场景 CH 是 ElasticSearch 的很好替代;BYOC 模式 能显著降低分析型 SaaS 的计算加价。
SECTION 12
一页纸行动清单
🚀 上线前
写副本隔离 + failover 方案
Keeper ≥3 节点独立部署
背压队列(Kafka 或自研)——没有它别上生产
表分区键评审 + sorting key 设计评审
CI 跑 ≥2 节点 + Keeper 集群测试,覆盖生产版 / master / 目标版
✍️ 写入侧
攒批 insert,每 insert ≈ 1 part,按分区攒批
用 S3 必开 Compact parts;考虑热盘缓冲
MV 数量与内存预算管控,异常 MV 自动熔断
幂等重试设计,防重复数据
🔍 查询侧
实时查询 max_threads=1,负载压 40% 以下保 p99
max_concurrent_queries 必须设置
四规则查询评审(sorting key → PREWHERE → IN → 重算子)
⬆️ 升级与变更
滚动升级 SOP:新版本加副本 → 读 → 写 → 切流 → 逐个升
新版本发布等 ≥1 个月;升级期冻结 DDL
用 system.query_log 回放真实查询做回归
settings diff 自动化
📡 监控
merge 队列、复制延迟、DDL 队列、Keeper 延迟、只读表、segfault 告警
团队熟读 system.query_log / processes / part_log
副本下线走多步流程(摘流 → 等 → kill → 关机)
🆘 保命
保留 50GB 删表保护
备份 + 恢复演练(备份没恢复过等于没有)
index_granularity ≥ 128;警惕高基数聚合状态列
附:原文没有但值得补的三点
ClickHouse Keeper 替代 ZooKeeper :新部署直接用 Keeper(C++ 实现、与 CH 同栈、运维负担更小),监控口径一致。
async inserts :作者评价"pretty limited",但写入端没有队列时至少打开它(async_insert=1 + wait_for_async_insert 权衡),是最简单的服务端攒批缓冲。
官方态度风险 :zero-copy 被创始人定性"数年内不会生产可用",社区认为官方在保护 Cloud 商业模式。架构押在 zero-copy 上要有 Plan B(热/冷分层随时可退)。
文中成本数字(300TB×10 副本、500MB/s 扫描等)是作者 2025 年的经验值,硬件与版本演进后建议当数量级参考,而非精确值。
解读整理:Keybo · 原文 © Tinybird(Javi Santana)· 引用的 HN 评论归原作者所有
配图由 xAI Imagine 生成 · 技术图解为手工 SVG,与原文机制一一对应