ClickHouseNotes

第 28 章:故障排查

zjc 于 2026-01-28 发布

这是《ClickHouse 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 故障排查要先确定故障域:客户端、网络、ClickHouse 服务、存储、Keeper、上游写入还是查询本身。本章给出一套可复用的排查框架。

28.1 排查框架

1. 确认影响面:单查询、单表、单节点还是集群
2. 确认时间线:开始时间、变更、流量峰值
3. 检查服务存活和端口
4. 检查资源:CPU、内存、磁盘、网络
5. 检查 system.processes
6. 检查 query_log / part_log / error log
7. 检查副本和 Keeper
8. 采取止血动作
9. 事后修复根因

28.2 服务不可用

检查:

curl -sS 'http://ch-01:8123/ping'
systemctl status clickhouse-server
ss -lntp | grep -E '8123|9000'

常见原因:

原因 特征
磁盘满 启动或写入失败
配置错误 启动直接退出
内存不足 进程退出或系统 OOM
端口冲突 监听失败
依赖 Keeper 不可达 副本只读或 DDL 失败
DNS 解析失败 远程节点连接异常

28.3 查询超时

运行中查询:

SELECT
    query_id,
    elapsed,
    read_rows,
    read_bytes,
    memory_usage,
    query
FROM system.processes
ORDER BY elapsed DESC;

止血:

KILL QUERY WHERE query_id = 'target-query-id';

随后检查:

  1. 是否分区未过滤;
  2. 是否扫描超大列;
  3. 是否高基数聚合;
  4. 是否大 JOIN;
  5. 是否被合并或写入争抢 IO;
  6. 是否分布式某分片慢。

28.4 内存不足

错误常见为 MEMORY_LIMIT_EXCEEDED

排查:

SELECT query_id, query, memory_usage, read_bytes
FROM system.query_log
WHERE exception LIKE '%MEMORY_LIMIT%'
ORDER BY event_time DESC
LIMIT 20;

处理:

  1. 增加过滤条件;
  2. 减少读取列;
  3. 降低分组基数;
  4. 使用近似聚合;
  5. 预聚合;
  6. 调整 max_memory_usage;
  7. 增加机器内存;
  8. 检查并发队列。

28.5 Too many parts

查看:

SELECT table, partition, count() AS parts, sum(rows) AS rows
FROM system.parts
WHERE active
GROUP BY table, partition
ORDER BY parts DESC
LIMIT 20;

止血:

  1. 暂停非关键写入;
  2. 降低补数并发;
  3. 增大批次间隔;
  4. 处理磁盘 IO 瓶颈;
  5. 必要时限制查询流量。

根因修复是调整写入频率、分区粒度或容量,而不是频繁执行 OPTIMIZE。

28.6 磁盘满

SELECT name, path, total_space, free_space
FROM system.disks
ORDER BY free_space;

处理顺序:

  1. 停止或限流写入;
  2. 检查异常大表和临时文件;
  3. 确认 TTL 是否生效;
  4. 删除可安全删除的过期分区;
  5. 扩容磁盘;
  6. 恢复写入并观察合并。

不要手工删除数据目录中的 part,除非有明确恢复方案。

28.7 副本异常

SELECT
    database,
    table,
    replica_name,
    is_readonly,
    queue_size,
    absolute_delay,
    last_queue_exception
FROM system.replicas;

处理:

现象 方向
readonly Keeper 连接和元数据
queue 增长 网络、磁盘、源副本
delay 高 同步落后
part missing 从健康副本拉取或恢复
metadata mismatch 表结构一致性

28.8 Kafka 无数据

排查:

SELECT database, table, consumer_id, assignments.topic
FROM system.kafka_consumers;

检查:

  1. topic 是否正确;
  2. group offset 是否越界;
  3. 消息格式是否匹配;
  4. 物化视图是否存在;
  5. 目标表是否有异常;
  6. 是否坏消息被跳过;
  7. 消费者是否停止。

28.9 数据不一致

对账:

SELECT count(), sum(amount)
FROM analytics.events_local
WHERE event_date = '2026-08-25';
SELECT sum(pv), sum(gmv)
FROM analytics.city_metric_local
WHERE metric_date = '2026-08-25';

差异来源:

  1. 物化视图创建时间;
  2. 历史回填重复;
  3. 过滤条件不同;
  4. 类型转换;
  5. 时区口径;
  6. 延迟数据;
  7. 消息丢失或重复。

28.10 应急预案

必备预案:

故障 动作
恶意大查询 kill、限流、降并发
磁盘满 停写、清理、扩容
Too many parts 限流写入、降合并压力
Keeper 多数派失效 停拓扑变更、恢复 Quorum
单节点故障 摘除流量、副本恢复
数据误删 停写、备份恢复
Kafka 积压 降级、重放、扩消费者

本章小结

故障排查要先收敛影响面,再用系统表和日志定位资源或语义问题。止血动作要有限制和记录,根因修复要回到写入模型、表设计、容量规划和监控告警。

思考题

  1. 查询超时的第一排查动作是什么?
  2. MEMORY_LIMIT_EXCEEDED 如何处理?
  3. 为什么不能频繁 OPTIMIZE 解决 Too many parts?
  4. 副本 readonly 常见原因有哪些?
  5. 数据不一致应从哪些口径入手?