先查system.replicas定位只读表及延迟:关注is_readonly=1、replica_is_active是否为0、absolute_delay是否持续>300秒;若后者高但前者为1,说明同步卡在zookeeper协调;若replica_is_active=0,则zookeeper连接已断或会话过期。

查 system.replicas 确认只读表和延迟指标
只读状态不是凭空出现的,system.replicas 是第一手线索。执行查询后重点关注三个字段:is_readonly=1 的表、replica_is_active 是否为 0、以及 absolute_delay 是否持续 >300(秒)。如果 absolute_delay 高但 replica_is_active=1,说明副本还在尝试同步,但卡在 ZooKeeper 协调环节;如果 replica_is_active=0,基本可断定 ZooKeeper 连接已断或会话过期。
常见误判点:仅看 is_readonly 就动手删 ZK 节点——实际可能只是单个副本临时失联,ZooKeeper 自身仍健康。务必先交叉验证。
用 nc + stat 检查 ZooKeeper 实时连接与会话状态
别依赖 ClickHouse 日志里的模糊提示,直接穿透到 ZooKeeper 层。用 echo stat | nc zk1.clickhouse 2181 获取原始响应,关键看两行:
-
Mode: follower或leader—— 如果显示standalone或无响应,说明集群分裂或节点宕机 -
Zxid:后的十六进制数 —— 连续多次执行,若该值长时间不递增,说明写请求压根没被处理
注意:Latency min/avg/max 中的 max 若超过 50ms,尤其伴随大量 OutstandingRequests(未完成请求数)>10,就是典型过载信号。此时 ClickHouse 的心跳包很可能被排队,触发只读保护。
定位 ZooKeeper 压力来源:看 dataLogDir 和 merge 频次
ZooKeeper 不是瓶颈,是压力的“显影液”。真正压垮它的,往往是 ClickHouse 侧高频小批量写入和无节制的后台 merge:
-
dataLogDir和dataDir是否共用同一块磁盘?共用时,ZK 日志刷盘会和 ClickHouse 数据写入抢 IO,iostat -x 1 5中%util持续 >85% 就是铁证 - 查
system.merges:如果elapsed很小但merge_reason大量是REPLACED或TTL,说明表配置了高频 TTL 或重复插入导致碎片化,间接抬高 ZK 的协调次数 - ReplicatedMergeTree 表的
zookeeper_path是否嵌套过深?比如/clickhouse/tables/prod/us-east/xxx/replicas/node1—— 路径越长,ZK 序列化/反序列化开销越大
一个容易被忽略的事实:auxiliary zookeeper 功能虽已合入主线,但默认不启用。如果你的集群有多个业务线共用一套 ZK,必须手动在 config.xml 中为不同表指定独立 zookeeper 配置段,否则压力无法分流。
修复前必须做的三件事:停写、清队列、验权限
别急着 rmr ZK 节点。在执行任何清理前,确认:
- 业务侧是否已暂停向问题表写入?继续写入会导致 ZK 队列进一步堆积,修复窗口期缩短
- ClickHouse 节点本地的
queue_size是否仍在增长?用SELECT queue_size, inserts_in_queue FROM system.replicas WHERE is_readonly = 1实时观察。若inserts_in_queue > 0,说明还有积压任务没被 ZK 接收,此时删 ZK 节点只会让副本彻底失联 -
/var/lib/clickhouse/目录下对应表的metadata/和data/子目录是否有写权限?权限错误(如被chown错误修改)也会让 ClickHouse 主动进入只读模式,而非 ZK 问题
最危险的操作是:在没确认 replica_is_active=0 的前提下,直接在 ZK 中删除 /replicas/xxx 节点。这会导致副本元数据永久丢失,恢复时只能靠人工导入,且极易引入数据不一致。











