你去餐厅点单,过去是后厨做完这一份才确认;现在变成先攒几桌的单,再一起出菜。这样更高效,但等待时间、出错方式和“已经做好”的含义都可能不同。ClickHouse 的一次补丁升级,据供稿者核对源码标签后发现,就把默认 INSERT(向数据库写入数据)从同步切到了异步。问题不只在性能,而在于团队可能根本不知道系统承诺已经变了。
ClickHouse 是面向日志、指标和大规模报表的列式数据库——数据按列组织,方便快速聚合扫描。本文涉及的版本、参数和效果均来自同一篇 Reddit 帖文;帖子引用了源码、变更记录和官方文档,但这些原始载体未分别提供,因此下述发现仍需独立复核。
三天之间,默认值变了
据该帖作者 Designer_Age7745 核对版本标签,async_insert 的默认值在 v26.2.3.2-stable 中还是 0,到了三天后的 v26.2.4.23-stable 已变成 1。后续列出的 v26.3.29.7-lts、v26.7.6.57-stable 和 v26.8.2.7-lts 也都是 1。
async_insert 控制 INSERT 是否走异步路径。同步写入通常等服务器完成当前写入后再确认;异步写入则先把多个小 INSERT 汇入缓冲区,再成批刷新,也就是 flush 到数据库。这样能减少数据 part——ClickHouse 写入时生成的数据片段——避免大量小写入制造过多碎片。
这项能力并非突然出现。据 ClickHouse 官方材料,异步写入在 2021.11 已推出,24.2 加入自动调节缓冲刷新时间的算法,26.1 又统一了它与物化视图的去重机制。官方直到 26.3 LTS 的发布文章才正式宣布默认开启。争议恰恰在这里:帖子称,实际切换提前发生在 26.2 的补丁版本中。
补丁版本通常被团队理解为修复问题、尽量保持兼容,而不是改变核心行为。ClickHouse 未必严格遵循语义化版本,但默认写入路径在补丁升级中变化,仍会超出许多运维团队的预期。
异步,不等于立刻返回
默认开启异步写入,并不意味着客户端把数据交出去就马上收到成功。帖子称,wait_for_async_insert 的默认值仍是 1,客户端会等缓冲区完成 flush 后才返回。因此,它仍然会阻塞,只是服务器在等待期间可以合并多次小写入。
代价是可感知的延迟。按帖子给出的配置,adaptive timeout——系统自动决定何时刷新缓冲区的等待窗口——介于 50 至 200 毫秒。这个范围可能受版本和配置影响,发布前应以目标版本源码与设置文档复核。
异步路径也不是对所有 INSERT 生效。帖子称,INSERT ... SELECT,也就是把查询结果直接写入另一张表,仍走同步路径,服务器会记录原因 insert query has select。单次写入超过 async_insert_max_data_size 的 10 MiB 上限时,也会绕过缓冲区直接写盘。
性能收益之外,还有判断风险
对频繁提交约 200 行小 INSERT 的生产端,合并写入可能缓解 Too many parts 错误,而且生产程序不用修改。不过,效果仍取决于写入频率、表结构、刷新策略和集群负载,不能把它理解成必然消除故障。
更值得警惕的是语义和监控。客户端收到成功、查询已经能读到数据、数据已经安全持久化,是三个不同节点。默认执行路径改变后,如果文档仍描述旧行为,团队排查延迟或丢数时可能从错误前提出发。
据 ClickHouse GitHub Issues,2026 年 8 月还有用户报告:默认异步路径的 INSERT 不会增加常用的 Query 和 InitialQuery 计数器,只有更专门的 InsertQuery、AsyncInsertQuery 会增长。依赖 Query 作为分母的仪表盘,可能因此少算写入请求。换回同步路径后,计数又恢复。这说明默认值变化不仅影响数据流,也可能改变运维人员看到的系统状态。
团队可以先查询 system.settings。若 async_insert 显示 value=1 且 changed=0,按帖子解释,这表示 1 是服务器默认值,而不是团队主动配置的结果。
局限与未知
- 帖子称官方最佳实践仍写着“默认同步”,但材料没有附上独立核验结果,文档现状存在不确定性。
- 变更归属也互相冲突:帖子称
CHANGELOG.md把它列入 26.3 LTS,SettingsChangesHistory.cpp却归入 26.2。 - 全部关键论断来自同一篇帖子,且原文末尾以孤立字母“D”截断,可能存在内容缺失。升级前应针对实际版本复核源码、设置和监控口径。