Linux下Docker Compose里运行的Clickhouse故障诊断脚本
在 ClickHouse 所在服务器的 docker-compose 项目目录执行chmodx ch_emergency_diag.sh ./ch_emergency_diag.sh /data/clickhouse-docker clickhouse#!/bin/bash# # 脚本名: ch_emergency_diag.sh# 用途: Docker Compose 中 ClickHouse 意外中断后的系统化诊断增强可分段复制版# 哲学优化原则:# 奥卡姆剃刀 - 只收集能直接导向根因的最小信息# 辩证法 - 揭示症状间的矛盾如OOM实为磁盘满# 实用主义 - 输出可立即操作的恢复提示、可复制命令# 整体论 - 提示关联宿主机、Docker Daemon、监控、ZK的全链路检查步骤# 核心特性每段代码可单独复制到Linux终端执行所有容器ID/挂载路径/分区名高亮可复制# 用法: ./ch_emergency_diag.sh [compose项目目录] [ClickHouse服务名]# 示例: ./ch_emergency_diag.sh /opt/clickhouse clickhouse# set-euopipefail# ----------------------------- 【单段可复制终端执行】全局常量与颜色定义 --------------------------------------# 入参赋值COMPOSE_DIR${1:-.}# docker-compose.yml 所在目录SVC_NAME${2:-clickhouse}# docker-compose 中的服务名LOG_TAIL200# 抓取容器日志行数TIMESTAMP$(date%Y%m%d_%H%M%S)DIAG_ROOT/tmp/ch_diag_${TIMESTAMP}mkdir-p$DIAG_ROOT# 统一存放所有可复制关键ID/路径文件KEY_INFO_FILE${DIAG_ROOT}/ch_diag_key_info.txt$KEY_INFO_FILEecho 所有可复制关键信息汇总容器ID/挂载卷/分区/退出码 $KEY_INFO_FILE# 颜色输出RED\033[0;31mGREEN\033[0;32mYELLOW\033[1;33mWHITE\033[1;37mNC\033[0m# 工具函数info(){echo-e${GREEN}[INFO]${NC}$*;echo[正常]$*$KEY_INFO_FILE;}warn(){echo-e${YELLOW}[WARN]${NC}$*;echo[警告]$*$KEY_INFO_FILE;}err(){echo-e${RED}[ERROR]${NC}$*;echo[严重异常]$*$KEY_INFO_FILE;}section(){echo-e\n${YELLOW}$1${NC};echo-e\n【模块】$1$KEY_INFO_FILE;}# 打印高亮可复制值核心所有ID/路径统一走这个函数输出print_copy(){locallabel$1localval$2echo-e${WHITE}【可复制$label】:${RED}$val${NC}echo$label$val$KEY_INFO_FILE}# 输出可直接执行的命令print_cmd(){echo-e${CYAN}[可直接执行命令]${NC}$1echo执行命令$1$KEY_INFO_FILE}# ----------------------------------------------------------------------------# ----------------------------- 【单段可复制终端执行】前置环境校验 --------------------------------------section前置环境校验# 切换compose目录cd$COMPOSE_DIR||{err无法进入compose项目目录$COMPOSE_DIR;exit1;}print_copyCompose项目工作目录$COMPOSE_DIRprint_copy目标服务名称$SVC_NAME# 校验docker-compose可用性if!command-vdocker-compose/dev/null;thenerrdocker-compose 命令不存在请安装或切换 docker compose v2exit1fiinfodocker-compose 环境校验通过# 校验jq容器元数据解析无则降级HAS_JQ1if!command-vjq/dev/null;thenwarn未安装jq容器挂载路径解析会简化输出建议执行 yum install jq / apt install jqHAS_JQ0fi# 【单段可复制终端执行】步骤1: 容器基础状态、CID、退出码、OOM标记 section1. 容器状态与退出码核心可复制容器ID# 列出compose服务全部容器docker-composeps-a$SVC_NAME2/dev/null||true# 获取容器CIDCID$(docker-composeps-q$SVC_NAME2/dev/null||true)if[[-z$CID]];thenerr未找到compose服务$SVC_NAME对应的容器print_cmddocker ps -a | grep$SVC_NAMEexit1fiprint_copy容器完整CID$CID# 读取容器状态元数据EXIT_CODE$(dockerinspect$CID--format{{.State.ExitCode}}2/dev/null||echounknown)OOM_KILLED$(dockerinspect$CID--format{{.State.OOMKilled}}2/dev/null||echounknown)IS_RUNNING$(dockerinspect$CID--format{{.State.Running}}2/dev/null||echofalse)print_copy容器退出码ExitCode$EXIT_CODEprint_copy是否被OOM杀死OOMKilled$OOM_KILLEDprint_copy容器当前运行状态Running$IS_RUNNING# 退出码故障预判case$EXIT_CODEin137)warn- SIGKILL(137)容器内存超限OOM kill / 手动docker kill;;139)warn- SIGSEGV(139)ClickHouse段错误程序/内存硬件异常;;143)info- SIGTERM(143)正常优雅停止编排系统主动关停;;1|2)warn- 应用内部异常退出优先查看容器日志;;0)info- 正常退出无崩溃;;esac# 提取容器资源限制mem_limit/cpu_limit存入文件dockerinspect$CID${DIAG_ROOT}/container_raw_meta.jsoninfo容器完整元数据已保存${DIAG_ROOT}/container_raw_meta.json# 解析宿主机挂载卷关键数据目录映射故障高频考点section1.1 容器数据卷挂载映射宿主机路径可复制if[[$HAS_JQ-eq1]];thenMOUNT_RAW$(dockerinspect$CID|jq-r.[].Mounts[] | 宿主机:.Source → 容器内:.Destination)echo$MOUNT_RAW${DIAG_ROOT}/volume_mapping.txtecho$MOUNT_RAWprint_copy容器卷映射完整清单查看文件${DIAG_ROOT}/volume_mapping.txtelsewarn无jq工具手动查看挂载命令print_cmddocker inspect$CID| grep -A10 Mountsfi# 【单段可复制终端执行】步骤2: 容器崩溃日志留存与关键词提取 section2. 容器崩溃日志采集尾部${LOG_TAIL}行LOG_FILE${DIAG_ROOT}/ch_container_last_logs.logdocker-composelogs--tail$LOG_TAIL$SVC_NAME$LOG_FILE2/dev/null||truecat$LOG_FILEinfo容器日志完整存档路径$LOG_FILEprint_copy故障日志文件路径$LOG_FILE# 预定义故障标记变量辩证法关联冲突症状DISK_FULL0;MEM_EXCEED0;CHECKSUM_ERR0;MANY_PARTS0QUERY_FLOOD0;PERM_ERR0;IO_ERR0;ZK_ERR0BROKEN_PART_RAW# 扫描日志关键字grep-qino space left on device$LOG_FILEDISK_FULL1||truegrep-qimemory limit.*exceeded$LOG_FILEMEM_EXCEED1||trueBROKEN_PART_RAW$(grep-iEchecksum mismatch|corrupted|broken part$LOG_FILE|head-3)[[-n$BROKEN_PART_RAW]]CHECKSUM_ERR1||truegrep-qitoo many parts$LOG_FILEMANY_PARTS1||truegrep-qitoo many simultaneous queries$LOG_FILEQUERY_FLOOD1||truegrep-qipermission denied$LOG_FILEPERM_ERR1||truegrep-qiread-only file system\|i/o error\|blk error$LOG_FILEIO_ERR1||truegrep-qizookeeper session expired\|zk connection timeout$LOG_FILEZK_ERR1||true# 打印故障标记状态section2.1 日志故障特征标记汇总echo磁盘满(DISK_FULL)$DISK_FULL| 内存超限(MEM_EXCEED)$MEM_EXCEEDecho数据损坏(CHECKSUM_ERR)$CHECKSUM_ERR| 分区过多(MANY_PARTS)$MANY_PARTSecho并发过载(QUERY_FLOOD)$QUERY_FLOOD| 权限错误(PERM_ERR)$PERM_ERRechoIO/只读挂载(IO_ERR)$IO_ERR| ZK连接异常(ZK_ERR)$ZK_ERRif[[-n$BROKEN_PART_RAW]];thenerr检测到损坏分区记录$BROKEN_PART_RAWprint_copy日志损坏分区原始信息$BROKEN_PART_RAWecho$BROKEN_PART_RAW${DIAG_ROOT}/broken_part_list.txtfi# 【单段可复制终端执行】步骤3: 辩证法矛盾关联分析OOM≠单纯内存可能磁盘/IO导致 section3. 矛盾冲突关联排查OOM/磁盘/IO联动校验# 矛盾链1标记OOM时强制校验宿主机磁盘空间if[[$OOM_KILLEDtrue||$EXIT_CODE137]];thenwarn【辩证矛盾点】容器OOM杀死先校验是否磁盘占满导致内存映射失败info宿主机磁盘整体快照df-h${DIAG_ROOT}/host_disk_snapshot.txtcat${DIAG_ROOT}/host_disk_snapshot.txtinfo宿主机inode使用率df-i${DIAG_ROOT}/host_inode_snapshot.txtcat${DIAG_ROOT}/host_inode_snapshot.txtprint_cmddu -sh$(dockerinspect $CID|jq-r.[].Mounts[0].Source)/* | sort -rh | head -10fi# 矛盾链2IO错误/只读挂载检查宿主机内核磁盘报错if[[$IO_ERR-eq1]];thenwarn【辩证矛盾点】IO异常读取内核磁盘错误日志DMESG_IO_LOG${DIAG_ROOT}/host_disk_io_dmesg.txtdmesg-T|grep-iext4\|xfs\|I/O error\|ro filesystem|tail-30$DMESG_IO_LOGcat$DMESG_IO_LOGprint_cmdcat /proc/mounts | grep ro,fi# 矛盾链3ZK报错联动集群复制故障if[[$ZK_ERR-eq1]];thenwarn【辩证矛盾点】ZK会话超时集群复制/分布式表会崩溃print_cmddocker exec$CIDcat /etc/clickhouse-server/config.xml | grep ZooKeeperprint_cmdtimedatectl status # 检查宿主机时钟偏移fi# 【单段可复制终端执行】步骤4: 宿主机资源全局快照 section4. 宿主机全局资源快照# 内存快照info宿主机内存/swap状态free-h${DIAG_ROOT}/host_mem_snapshot.txtcat${DIAG_ROOT}/host_mem_snapshot.txt# 系统负载uptime${DIAG_ROOT}/host_loadavg.txtcat${DIAG_ROOT}/host_loadavg.txt# 抓取docker daemon日志容器崩溃源头之一infoDocker守护进程近10分钟日志journalctl-udocker.service--since10 min ago--no-pager|tail-50${DIAG_ROOT}/docker_daemon_log.txt# 【单段可复制终端执行】步骤5: 容器运行时内部诊断容器存活才执行 section5. 容器内部ClickHouse实时指标仅容器Running时生效if[[$IS_RUNNINGtrue]];theninfo容器正在运行抓取ClickHouse系统指标、长查询、复制队列# 1. 基础指标dockerexec$CIDclickhouse-client-q SELECT metric, value FROM system.metrics WHERE metric IN (MemoryTracking,Query,Merge,MaxPartCountForPartition,ZooKeeperSessionAlive) ${DIAG_ROOT}/ck_runtime_metrics.txt# 2. 长耗时查询dockerexec$CIDclickhouse-client-q SELECT query_id, user, database, elapsed, memory_usage FROM system.processes ORDER BY elapsed DESC LIMIT 20; ${DIAG_ROOT}/ck_long_query.txt# 3. 复制队列积压集群核心故障点dockerexec$CIDclickhouse-client-q SELECT database, table, partition, name, is_detached, reason FROM system.replication_queue LIMIT 100; ${DIAG_ROOT}/ck_replication_queue.txt# 4. 损坏分区查询dockerexec$CIDclickhouse-client-q SELECT database, table, partition, name FROM system.parts WHERE active0 AND broken1; ${DIAG_ROOT}/ck_broken_parts_query.txtinfo容器内所有指标文件目录$DIAG_ROOTelsewarn容器当前未运行跳过ClickHouse内部实时指标采集print_cmddocker-compose up -d$SVC_NAME# 如需临时启动采集指标fi# 【单段可复制终端执行】步骤6: 分场景一键恢复可复制命令实用主义 section6. 分故障场景 可直接复制执行修复命令汇总echo-e${WHITE} 故障场景一键操作命令 ${NC}# 场景1 OOM内存超限if[[$OOM_KILLEDtrue||$EXIT_CODE137||$MEM_EXCEED-eq1]];thenechoecho[1] OOM内存超限修复操作print_cmdgrep -A5$SVC_NAME$COMPOSE_DIR/docker-compose.yml | grep mem_limitprint_cmddocker exec$CIDcat /etc/clickhouse-server/config.xml | grep max_server_memory_usageprint_cmddocker-compose down docker-compose up -d$SVC_NAME# 修改内存限制后重启fi# 场景2 磁盘满if[[$DISK_FULL-eq1]];thenechoecho[2] 磁盘空间耗尽应急清理print_cmddocker exec$CIDclickhouse-client -q\ALTER TABLE 库名.表名 DROP PARTITION 分区ID\print_cmdmv /宿主机数据目录/对应分区文件夹 /备份目录/detached/fi# 场景3 数据分区损坏if[[$CHECKSUM_ERR-eq1-n$BROKEN_PART_RAW]];thenechoecho[3] 损坏分区隔离恢复不删除数据先启动服务print_cmdcd$(dockerinspect $CID|jq-r.[].Mounts[0].Source)/data/库名/表名/print_cmdmkdir -p detached mv 损坏分区文件夹 detached/print_cmddocker-compose restart$SVC_NAMEfi# 场景4 IO/只读文件系统if[[$IO_ERR-eq1]];thenechoecho[4] 磁盘IO/只读挂载排查print_cmdmount -o remount,rw /数据挂载盘设备print_cmdfsck -n /dev/磁盘设备 # 停机后执行磁盘校验fi# 场景5 分区过多合并风暴if[[$MANY_PARTS-eq1]];thenechoecho[5] 分区堆积手动合并print_cmddocker exec$CIDclickhouse-client -q\OPTIMIZE TABLE 库名.表名 FINAL\fi# 场景6 ZK集群连接异常if[[$ZK_ERR-eq1]];thenechoecho[6] Zookeeper连接排查print_cmddocker exec$CIDcurl -v zk地址:2181fi# 【单段可复制终端执行】步骤7: 整体论全链路手工检查清单 section7. 整体论全链路上下游扩展排查手工执行echo1. Docker层journalctl -u docker.service 查看容器启停完整日志echo2. 内核层dmesg -T 硬件/内存/磁盘底层报错echo3. 监控联动Grafana对照故障时间点容器CPU/内存/磁盘IO曲线echo4. 上游业务应用连接池、重试策略、批量写入是否触发写入风暴echo5. 集群依赖ZooKeeper集群状态、节点时钟同步、网络连通性echo6. 备份校验确认ClickHouse分区备份可用性损坏场景用于恢复# 【单段可复制终端执行】最终诊断汇总输出 section诊断执行完成 · 关键文件汇总info本次诊断全部数据存放目录${DIAG_ROOT}print_copy关键信息一键复制文件所有CID/路径/故障摘要$KEY_INFO_FILEprint_cmdcat$KEY_INFO_FILE# 终端一键查看所有可复制ID、路径echowarn操作优先级建议echo 1. 磁盘100%占用 → 优先扩容/清理分区echo 2. OOM被系统杀死 → 调整compose mem_limit与CK内存参数匹配echo 3. 数据校验损坏 → 隔离损坏分区禁止直接重启覆盖数据echo 4. IO只读挂载 → 停机检查磁盘硬件修复文件系统echo 5. ZK会话超时 → 同步服务器时钟检查ZK集群负载echo-e${GREEN}${NC}