1. 首页
  2. 后端监控
  3. 一次 ClickHouse 服务器磁盘告警的排查与修复实录

一次 ClickHouse 服务器磁盘告警的排查与修复实录

一只会飞的鱼儿 1小时前 ⋅ 1 阅读
ad

​

摘要:一台预发布环境的 ClickHouse 服务器触发磁盘告警,40G 系统盘使用率飙到 81%。排查后发现,是 ClickHouse 的“日志预留机制”与系统日志刷屏互相放大,形成了恶性循环。本文记录完整的排查思路、根因分析和三步修复方案,最终使用率从 81% 降到 27%。

一、告警背景

某天收到监控告警:预发布环境一台 ClickHouse 服务器磁盘使用率超过 80%。这台机器是 40G 系统盘,运行着 clickhouse-server(systemd 服务,数据盘与系统盘分离)。

第一反应是“又该清日志了”——但这次远不止清理日志这么简单。

二、排查过程

1. 定位空间去向

df -h /
# /dev/vda3 40G 30G 7.3G 81% /
du -sh /var/log
20G /var/log

40G 的盘,光 /var/log 就占了 20G。继续往下看:

ls -lh /var/log/syslog /var/log/syslog.1
# -rw-r----- 1 syslog adm 5.2G /var/log/syslog
# -rw-r----- 1 syslog adm 11G /var/log/syslog.1
journalctl --disk-usage
Archived and active journals take up 3.9G in the file system.

构成很清晰:syslog 5.2G + syslog.1 11G + journal 3.9G ≈ 20G。

2. 查看 syslog 里到底在写什么

tail -100 /var/log/syslog

结果令人意外:100% 的内容都是 clickhouse-server 的异常堆栈,以极高的频率刷屏。其中反复出现两条关键错误:

Poco::Exception. Code: 1000, e.code() = 0,
File access error: /var/log/clickhouse-server/clickhouse-server.log
Cannot add message to the log: Reserved 1.00 MiB on local disk `default`,
having unreserved 7.48 GiB

堆栈路径:

AsynchronousMetrics::update
→ OwnSplitChannel::log
→ Poco::FileChannel::log
→ RotateBySizeStrategy::mustRotate
→ FileException

3. 几个反常现象

进一步排查发现几个互相矛盾的线索:

  1. 服务并没有崩溃:systemctl status clickhouse-server 显示服务已连续运行 45 天,NRestarts=0,内存和 CPU 都正常。
  2. CK 自身的日志文件是 0 字节:/var/log/clickhouse-server/clickhouse-server.log 和 err.log 从几天前某时刻起一直是 0 字节——也就是说,CK 早就不再写自己的日志了。
  3. 操作系统层写入正常:以 clickhouse 用户身份做 shell 写入测试完全正常,说明不是文件系统权限或磁盘真的写满的问题。

4. 根因:ClickHouse 的“日志预留机制”

把这些线索串起来,真相浮出水面:

ClickHouse 有一个内置的磁盘预留机制(logger reservation):为了避免日志写满磁盘影响数据写入,CK 在写日志前会检查磁盘的“未预留空间”。当磁盘空闲空间低于某个水位时,CK 会拒绝写入自己的日志文件,抛出 Cannot add message to the log: Reserved 1.00 MiB ... 异常。

问题在于,这个异常本身也写不进日志文件,于是它被打到了 stderr → 被 systemd 捕获 → 进入 journald → rsyslog 转写到 syslog。而 syslog 和 journal 都在同一个 40G 系统盘上。

于是形成了一个恶性循环:

磁盘空闲低
→ CK 拒绝写自身日志(预留机制)
→ 异常堆栈打到 stderr
→ journald / syslog 疯狂增长
→ 磁盘空闲更低
→ 刷屏更凶
→ ……循环

一天能增长 1.5G 的 syslog,就是这么来的。

5. 为什么现有防护没拦住

排查中还发现三个配置缺陷,让这个循环得以持续放大:

  1. 没有为 clickhouse 配置 logrotate:系统里根本没有 /etc/logrotate.d/clickhouse-server,CK 的日志文件没有大小上限和轮转策略。
  2. rsyslog 轮转频率不够:默认 weekly 轮转,扛不住每天 1.5G 的增长,syslog.1 攒到了 11G。
  3. journald 没有上限:未配置 SystemMaxUse,journal 目录涨到了 3.9G。

三、修复方案

分三步:先止血释放空间,再配置防护防止复发,最后重启验证。

第一步:释放磁盘空间

# 清空 syslog(truncate 保留 inode,rsyslog 文件句柄不受影响)
truncate -s 0 /var/log/syslog.1
truncate -s 0 /var/log/syslog
systemctl kill -s HUP rsyslog.service  # 通知 rsyslog 刷新文件句柄
journald 限制到 500M
echo 'SystemMaxUse=500M' >> /etc/systemd/journald.conf
systemctl restart systemd-journald  # 重启后自动清理到上限以下
journalctl --disk-usage  # 3.9G → 413.8M

小技巧:用 truncate 而不是 rm 清日志,可以避免 rsyslog 持有的文件句柄指向已删除文件(那样空间不会真正释放,直到进程重启)。truncate 后补一个 HUP,让 rsyslog 重新定位写位置即可。

第二步:配置日志轮转防护

给 CK 补上 logrotate:

cat > /etc/logrotate.d/clickhouse-server <<'EOF'
/var/log/clickhouse-server/*.log {
    size 100M
    rotate 5
    missingok
    notifempty
    compress
    delaycompress
    copytruncate
}
EOF

把 rsyslog 轮转改成按天 + 按大小双触发:

# /etc/logrotate.d/rsyslog 中:
# weekly → daily
# 增加 maxsize 1G
sed -i 's/^\([[:space:]]*\)weekly/\1daily/' /etc/logrotate.d/rsyslog
sed -i '/^[[:space:]]*rotate /a\ maxsize 1G' /etc/logrotate.d/rsyslog

journald 上限已经在第一步配置了 500M,与 logrotate 一起构成三道防线。

第三步:重启 clickhouse-server 并验证

systemctl restart clickhouse-server
sleep 20
systemctl status clickhouse-server --no-pager -l

验证四项:

验证项 结果
服务状态 active (running)
CK 日志恢复写入 clickhouse-server.log 从 0 字节恢复增长
syslog 刷屏停止 10 秒增长 0 字节
客户端正常响应 clickhouse-client --query "SELECT version()" 正常返回

最终磁盘状态:

/dev/vda3 40G 9.8G 28G 27% /
479M /var/log

81% → 27%,释放约 20G,告警解除。

四、经验总结

排查思路回顾

磁盘告警
→ df 看整体使用率
→ du 逐层定位大头目录(/var/log 占 20G)
→ 看日志内容(syslog 被什么刷屏)
→ 找刷屏源头(clickhouse-server 异常堆栈)
→ 反查刷屏原因(CK 日志预留机制拒绝写日志)
→ 检查防护配置缺口(logrotate / journald 上限)

三条教训

  1. 日志刷屏的源头往往是“日志写不进日志”。当 syslog 里全是某个进程的异常堆栈时,优先怀疑该进程自身的日志通道出了问题(权限、磁盘预留、文件被删),而不是先去查业务逻辑错误。
  2. 日志系统本身必须有硬限额。logrotate(按大小)、journald SystemMaxUse、rsyslog maxsize 三道防线缺一不可,否则任何一次刷屏都可能滚雪球。
  3. 预发布环境同样要配置完整。这类机器的日志策略经常被忽略,但预发布流量并不小,出问题的概率和线上是同一量级。

预防清单

  • 所有数据库组件(ClickHouse、MySQL 等)都配置 logrotate,按 size 触发
  • journald 配置 SystemMaxUse(建议 500M 以内)
  • rsyslog 轮转使用 daily + maxsize 双触发
  • 磁盘告警阈值设置在水位 80% 以下,留出排查时间
  • 收到告警先查“日志占了多少”,/var/log 通常是第一嫌疑

​

关于Webfunny

Webfunny专注于前端监控系统,前端埋点系统的研发。 致力于帮助开发者快速定位问题,帮助企业用数据驱动业务,实现业务数据的快速增长。支持H5/Web/PC前端、微信小程序、支付宝小程序、UniApp和Taro等跨平台框架。实时监控前端网页、前端数据分析、错误统计分析监控和BUG预警,第一时间报警,快速修复BUG!支持私有化部署,Docker容器化部署,可支持千万级PV的日活量!

  点赞 0   收藏 0
  • 一只会飞的鱼儿
    共发布88篇文章 获得10个收藏
全部评论: 0 条