ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

系统盘被syslog日志撑爆怎么办:日志风暴排查与根因修复实战

系统盘被syslog日志撑爆怎么办:日志风暴排查与根因修复实战 周二凌晨 2 点 14 分监控平台的一条告警把值班手机打亮一台生产服务器系统盘使用率直接飙到 98%几乎满盘。登录上去之后df -hT /显示根分区只剩 300MB 可用空间连正常的命令补全都开始卡顿。顺着du一路查下去矛头齐刷刷指向了/var/log/syslog和/var/log/messages——这两个日志文件加起来超过 60GB是 syslog 日志风暴把系统盘彻底撑爆了。这篇记录不是简单说一句“删掉日志文件就好了”就完事。日志爆盘这种事表面上看着像磁盘容量问题本质上一定是日志生成链路出了问题。我完整复盘了从告警触发、应急清理、定位根因到最后做日志限额与监控加固的全过程把中间踩过的坑和可复用的排查命令都整理了出来。如果你也是服务器运维、SRE或者自己管着一台云主机遇到“系统盘满了”并且大文件全是 syslog 的场景这篇文章应该能帮你少走不少弯路。1. 告警第一现场df -h 和 syslog 文件的诡异增长1.1 先从空间使用率和 inode 两个维度确认“满”的性质我接到告警后做的第一件事不是急着删文件而是先确认两个基础指标磁盘空间是否真的满了inode 是否够用。因为“系统盘满”有两种常见形态一种是容量被大文件占满另一种是文件数量过多把 inode 耗尽。后者哪怕df -h看着还有空间应用也照样创建不了新文件。当时的环境是 Debian 系服务器日志服务用的是 rsyslog配合 systemd-journald。我先执行了这两条命令df -hT / # 查看根分区的容量、已用、可用空间 df -i / # 查看根分区的 inode 使用情况结果很清晰/分区容量 200GB已用 98%可用空间只剩 300MB根分区 inode 使用率只有 23%所以不是文件数量爆掉纯粹是容量被一个大文件塞满了。接下来我用du一层层往下探测找到到底是哪个目录在吃掉系统盘du -xhd1 /var | sort -rh | head -20-x参数的意思是不要跨越文件系统边界避免把其他挂载点的统计数据也算进来-h是为了让输出更可读sort -rh按人类可读的大小倒序排序。输出里/var/log直接占掉了根分区 75% 的使用量而/var/log下面最大的两个文件就是find /var/log -type f -size 100M -exec ls -lh {} \;结果-rw-r----- 1 root adm 35G Dec 12 02:23 /var/log/syslog -rw-r----- 1 root adm 28G Dec 12 02:23 /var/log/kern.log -rw-r----- 1 root adm 2.1G Dec 12 02:18 /var/log/messages看到这个输出我已经基本确定了syslog 在疯狂写日志而且连内核日志kern.log也涨到了 28GB。这不太可能只是某个普通应用在打日志内核层面可能也在刷报错。1.2 用 stat 循环观察日志增长速度判断是偶发还是持续风暴光看到文件大还不够我还需要知道它现在到底还在不在涨、涨得多快。如果它已经停止增长了那可能只是历史积压如果它还在以每分钟几十 MB 的速度增长就必须立刻止损。这里我没有用tail -f直接盯着输出而是用stat做了一个 10 秒一次的轮询观察文件大小变化while true; do stat -c %s %n /var/log/syslog; sleep 10; done输出大致是这样的245364210 /var/log/syslog 248391401 /var/log/syslog 251430188 /var/log/syslog10 秒涨了约 3MB换算一下就是每分钟增长大约 18MB每小时能多出 1GB 以上。这说明日志风暴还在持续而且非常凶猛。如果不干预再过几十分钟系统盘空间会完全耗尽届时连 SSH 登录、写入临时文件、systemd 启动新服务都会受到直接影响。1.3 第一反应不要直接 rm 日志文件先处理“文件被占用”的隐患很多朋友一看磁盘满脑子里第一个念头就是rm -rf /var/log/syslog。这个操作在服务器上非常危险因为日志进程 rsyslogd 正握着这些文件的文件描述符。就算你把文件名删掉了只要进程不重启、不主动释放句柄被删除文件占用的磁盘空间并不会立刻归还你会发现df -h依然显示 98%然后陷入“我明明删了文件为什么空间没变”的困惑。判断是否存在这种被删除但未释放的文件用lsof L1lsof L1 | grep deleted这条命令会列出所有“被删除但还有进程持有”的文件。如果发现 rsyslogd 或者 journald 相关进程持有/var/log/syslog的 deleted 句柄那么单纯删除文件是没用的。正确做法是用truncate清空文件内容而不是删除文件名truncate -s 0 /var/log/syslog truncate -s 0 /var/log/kern.log truncate -s 0 /var/log/messagestruncate -s 0会把文件大小截断为 0但保留文件名也不影响 rsyslogd 持有的文件描述符空间会立刻释放。这是应急阶段处理大日志文件最安全的方式之一。2. 定位日志风暴的源头从 /var/log 到 journald 的层层追踪2.1 先 tail 看内容再按进程名统计刷屏来源空间暂时释放了但根因还没找到如果直接不管几分钟后日志又会重新把磁盘占满。我开始在日志内容里寻找线索。先用tail -n 200 /var/log/syslog看看正在写入的到底是什么日志。屏幕刷出来的内容高度重复Dec 12 02:23:11 prod-api patrol-agent[44111]: [ERROR] load_config: bad value for endpoint, retry after 3s Dec 12 02:23:11 prod-api systemd[1]: patrol-agent.service: Scheduled restart job, restart counter is at 531 Dec 12 02:23:14 prod-api patrol-agent[44134]: [ERROR] load_config: bad value for endpoint, retry after 3s Dec 12 02:23:14 prod-api systemd[1]: patrol-agent.service: Scheduled restart job, restart counter is at 532一个叫patrol-agent的内部巡检代理服务每隔 3 秒就崩溃重启一次每次崩溃都向 syslog 写入 ERROR 日志systemd 又记录一条 restart 事件。两个来源叠加在一起日志自然爆炸了。为了确认就是它在刷屏我用awk对最近 5000 条日志按进程名做了统计tail -n 5000 /var/log/syslog | awk {print $5} | sort | uniq -c | sort -rn结果非常明显4921 patrol-agent 79 systemd 0 kernel几乎每 5000 条日志里就有 4921 条来自 patrol-agent。这说明日志风暴就是它造成的不用再怀疑其他服务。2.2 用 journalctl 从系统日志维度交叉验证rsyslog 会记录日志但 systemd-journald 其实也把所有服务的标准输出和错误输出都捕获了一份。为了交叉验证我又从 journald 的角度看了一遍journalctl -u patrol-agent --since 1 hour ago --no-pager | wc -l journalctl --disk-usage前者统计了 patrol-agent 这一个服务最近一小时产生了多少条 journal 日志结果高达 4 万多条后者显示 journald 持久化日志占用的磁盘空间也有 12GB。这说明日志风暴的影响范围不局限于/var/log/syslog/var/log/journal底下的持久化日志同样在吞系统盘空间。我在这一步得到一个很重要的经验排查询问不能只看 rsyslog 的文件还要把 journald 算进来。如果只在 /var/log 下面找很可能漏掉 journal 目录导致清理完 messages/syslog 之后发现磁盘空间还是少了一大块。2.3 停止可疑服务验证日志是否停止增长发现可疑目标之后我没有马上改配置而是先把这个服务停掉验证日志增长速度是不是跟着停下来。systemctl stop patrol-agent然后再次用stat循环观察/var/log/syslog的大小变化。等了 30 秒文件大小几乎没动。这下基本锁定了根因patrol-agent 进程在疯狂刷错误日志触发点应该是它的配置文件中某个参数不可用导致它每次启动都读取失败、然后陷入 crash loop。顺着配置查下去发现是最近一次上线时运维平台把 patrol-agent 的连接 endpoint 改成了内网新地址但配置文件里的 endpoint 还是旧地址而且它没有做配置合法性校验遇到错误参数就抛异常崩溃然后被 systemd 反复拉起。这个循环每 3 秒一轮一晚上就积累了 60GB 日志。3. 日志为什么会刷爆磁盘轮转机制与常见故障模式3.1 logrotate 为什么没拦住这波日志风暴很多人会有疑问服务器上不是有 logrotate 吗日志文件应该每天或者每周轮转才对为什么还会被撑爆logrotate 确实存在但它有一个前提轮转是按照时间周期或者文件大小阈值触发的。默认配置通常是daily也就是每天执行一次轮转只保留 7 到 28 份历史日志。当日志生成速度达到每分钟 18MB 时一天就是几十 GBlogrotate 根本来不及在“磁盘爆掉”之前把旧的日志文件清掉。另外还要注意很多发行版的 logrotate 配置默认是按天轮转但没有配置size阈值也就不会因为文件尺寸过大而提前触发。这意味着只要日志风暴在两次轮转之间爆发系统盘就有被塞满的可能。/etc/logrotate.d/syslog里如果只写了daily没有size 100M之类的限制遇到半夜的日志风暴就只能祈祷磁盘够大了。3.2 journald 持久化是第二块隐形磁盘杀手除了 rsyslog 写的/var/log/syslogsystemd-journald 默认会在/var/log/journal下持久化保存日志。journald 也有自己的清理机制但它的默认空间上限是可配置的很多服务器没有配置SystemMaxUse于是它最多能用到所在文件系统容量的 10%如果分区是 200GBjournal 目录理论上就能膨胀到 20GB。更麻烦的是journald 的日志是二进制格式没法直接用tail查看普通运维同学如果不熟悉journalctl --disk-usage这条命令很容易忽略这块占用。这次故障里journal 目录占用了 12GB虽然不是最严重的一份但也是压垮系统盘的重要一环。3.3 常见的日志爆盘触发模式以及怎么快速判断我遇到过的日志刷爆系统盘场景大致可以归纳为四类每一种都有比较明显的判断特征故障模式典型表现快速判断方法应用进程 crash loopsystemd 反复拉起服务日志里出现大量相同报错和 restart 记录journalctl -u 服务名内核驱动/硬件报错kern.log快速增长内容包含 ata、nvme、link down、SError 等关键词tail -n 100 /var/log/kern.log看是否重复日志级别被误调为 debug原本不记录的 debug 信息全部写入日志文本量大增对比日志内容是否包含大量 trace/debug 关键词远程日志投递失败rsyslog 配置了远程转发但 endpoint 不可达消息在本地队列积压并落盘检查 rsyslog 配置中的 remote endpoint 连通性这几类模式的排查思路不太一样但共同点是先找到“什么在写日志”再分析“为什么写这么多”最后才考虑“怎么清理和限制”。直接删文件永远只能解决几分钟的问题。4. 清理止损与根因修复一次完整的处置记录4.1 应急阶段空间释放的操作顺序我已经在第一阶段用truncate把syslog和kern.log清空了但 journald 的 12GB 还没处理。这一步主要解决磁盘空间的“存量”问题。处理 journald 时用journalctl自带的 vacuum 命令journalctl --vacuum-size200M journalctl --vacuum-time2d--vacuum-size200M的意思是让 journald 清理历史归档日志直到总占用不超过 200MB--vacuum-time2d表示只保留最近 2 天的日志。两条命令可以同时执行也可以只选其中一条效果是立竿见影的。清理完这两块之后再看df -hT /根分区可用空间已经回到 120GB 以上。这个阶段注意一点不要在应急时想着“保留现场”把几十 GB 的日志先拷贝一份再清理这会让系统盘直接卡死。如果后续需要分析可以在日志文件被截断之前先tail几百行存成一个小文件够用了。4.2 根因修复不是改配置就行还要验证配置格式空间释放只算是止血patrol-agent 还在每 3 秒崩溃一次如果放任不管明天早上又会重复今天晚上的状况。我打开它的配置文件看到了问题所在endpoint old-internal-addr:8080这个地址已经是废弃的内网地址patrol-agent 启动时连不上这个 endpoint于是在初始化阶段抛异常。问题的关键不是地址写错了而是它把配置解析错误当成致命错误处理导致进程直接退出systemd 又把它拉起来形成了崩溃循环。我做了两步修正把配置文件里的 endpoint 改成当前可用的内网地址检查 patrol-agent 的 systemd unit 是否有限制重启频率。默认的Restartalways配合RestartSec0时会因为重启过快而加剧日志风暴。应该在 unit 里加上RestartSec10给崩溃恢复留出缓冲时间。修正配置后启动服务systemctl daemon-reload systemctl start patrol-agent然后继续用stat观察/var/log/syslog的增长情况。这次等了 5 分钟文件大小几乎没有变化systemctl status patrol-agent也显示稳定运行不再重启。根因才算真正解决。4.3 处置过程中的一个原则先止血再排查最后加固整个故障处置过程中我一直在提醒自己一个原则顺序不能乱。如果先花大量时间排查根因磁盘空间耗尽导致系统服务中断可能造成比日志爆盘更严重的故障如果只清理空间不排查根因那就是治标不治本过几个小时还要再折腾一遍只有先快速释放空间稳住局面再用工具定位日志来源最后修复并加固才是完整的闭环。这次故障从告警到根因处理完毕大概用了 40 分钟其中前 15 分钟都是在做空间释放和避免二次伤害真正定位根因反而只花了不到 10 分钟。如果一开始就慌慌张张把文件rm了可能现在还在跟“删除文件后磁盘空间没释放”的问题较劲。5. 防止下次再爆盘监控告警与日志限额的落地配置5.1 journald 必须显式设置空间上限和保留时间这次故障之后我第一时间去把 journald 的默认配置改了。文件在/etc/systemd/journald.conf常用的几个参数如下[Journal] Storagepersistent SystemMaxUse200M SystemMaxFileSize50M MaxRetentionSec7d MaxFileSec1day各参数含义Storagepersistent日志持久化到磁盘SystemMaxUse200Mjournald 所有归档日志总大小上限为 200MB这是最关键的一条防线SystemMaxFileSize50M单个 journal 文件最大 50MB超出就滚动创建新文件MaxRetentionSec7d日志最多保留 7 天MaxFileSec1day单个日志文件最长使用 1 天。修改之后重启服务让配置生效systemctl restart systemd-journald journalctl --disk-usage重启 journald 不会清空已有日志只是重新加载配置并触发归档整理。执行完journalctl --disk-usage确认一下变化即可。这一步做完journal 这块的爆盘风险基本被摁死了。5.2 logrotate 增加 size 阈值并确认轮转脚本可用rsyslog 侧的logrotate配置也要改。以本次服务器 Debian 系为例配置文件在/etc/logrotate.d/rsyslog。我在日志路径声明后面追加了size 100M条件并保留daily和compress/var/log/syslog /var/log/messages /var/log/kern.log { daily size 100M rotate 7 compress delaycompress missingok notifempty create 0640 syslog adm postrotate /usr/lib/rsyslog/rsyslog-rotate endscript }size 100M的作用是只要这些日志文件任何一个超过 100MB就算还没到轮转时间也会立即触发轮转。这比单纯靠daily可靠得多。delaycompress也很重要它会让上一次轮转出来的日志文件在下次轮转时才压缩避免 rsyslog 还在写文件时压缩进程抢文件句柄。配好之后用logrotate -d /etc/logrotate.d/rsyslog做一次 dry run 测试确认配置文件没有语法错误。想强制轮转一把验证效果的话可以用logrotate -f /etc/logrotate.d/rsyslog。5.3 rsyslog 层面的限流给日志风暴加一道总闸系统层面的防护不光要限制日志文件的体积还要防止某个应用在短时间内刷出大量日志。rsyslog 自带接收 socket 的速率限制本质上是“如果某个程序在短时间内发来太多日志多余部分直接丢弃”。新版 rsyslog 的写法是在/etc/rsyslog.conf里加载模块并设置参数module(loadimuxsock RateLimitInterval5 RateLimitBurst1000)老版本 rsyslog 用的是$SystemLogRateLimitInterval和$SystemLogRateLimitBurst这两个全局指令。含义是在 5 秒内同一个程序最多处理 1000 条日志消息超过部分直接丢弃。这样即使某个服务突然死循环刷日志冲击也会被限制在一个可控范围内不会直接把系统盘写满。需要注意速率限制设置得太小有可能误伤正常的业务日志比如高并发服务的访问日志可能超过这个阈值。所以限流值建议根据业务实际情况来调整可以先统计正常情况下的日志速率再留出 3 到 5 倍的余量。5.4 加一套磁盘水位监控并把 inode 也纳入告警范围日志限额只是后台防御真正让我们能在故障发生早期就发现问题的还是监控告警。现在我的服务器上至少会部署以下两个层级的告警磁盘容量水位根分区使用率超过 80% 告警超过 90% 触发高优先级告警inode 水位根分区 inode 使用率超过 85% 告警防止日志文件数量过多导致无法创建新文件。如果手头没有完整的监控平台用 cron 写一个简单的检查脚本也能起到类似作用#!/bin/bash THRESHOLD85 CURRENT$(df -h / | awk NR2 {print $5} | tr -d %) if [ $CURRENT -gt $THRESHOLD ]; then echo $(date %F %T) WARN root partition usage ${CURRENT}% /var/log/disk-watch.log # 这里可以接你自己的告警渠道例如短信、企业微信、钉钉机器人 fi把脚本放进 cron 每 5 分钟执行一次虽然比不上专业监控平台实时但至少能在系统盘真正被塞满之前给出一个缓冲窗口。5.5 架构层面把 /var/log 挪到独立分区或独立磁盘如果服务器短期内不能扩容系统盘还有一个更治本的方案把/var/log单独挂载到独立分区或者独立数据盘上。这样即使日志再次爆炸影响的也只是 /var/log 所在分区不会把整个系统盘拖垮系统核心服务不会因为写日志而中断。操作思路是先把新分区挂载到一个临时目录把现有/var/log下的内容 rsync 过去然后修改/etc/fstab让新分区在开机时挂载到/var/log。这一步一定要在日志量小的时候做并且做好备份。一旦/var/log独立挂载再配合前面说的日志限额和监控告警系统盘被 syslog 占满的概率就非常低了。6. 这次故障教会我的几件事复盘与可复用命令集6.1 一套完整的日志爆盘排查命令清单有些朋友可能看完上面的过程记不住具体命令。这里我把整套排查命令串成一条可以直接复制的清单方便你下次遇到“系统盘满了怀疑是日志撑爆”时按顺序执行# 1. 先看空间与 inode 两个维度 df -hT / df -i / # 2. 找大目录、大文件 du -xhd1 /var | sort -rh | head -20 find /var/log -type f -size 100M -exec ls -lh {} \; # 3. 观察日志增长速率 stat -c %s %n /var/log/syslog # 4. 统计日志来源进程 tail -n 5000 /var/log/syslog | awk {print $5} | sort | uniq -c | sort -rn # 5. 查看 journald 占用并清理 journalctl --disk-usage journalctl --vacuum-size200M # 6. 查找被删除但仍被进程占用的文件 lsof L1 | grep deleted这套命令不需要全都跑完很多时候第 1、2 步就能确定大方向第 4 步能直接锁定元凶第 6 步专门用来处理“rm 之后空间没释放”的疑难杂症。6.2 我踩过的三个容易复发的坑第一个坑是清理完日志之后忘记处理 journald。很多人只关注/var/log/messages或者/var/log/syslog却忽略了/var/log/journal下的二进制日志。journald 的默认空间上限如果没配它会在系统盘最紧张的时候再补一刀。第二个坑是配置文件改了服务也重启了但没观察足够长的时间就宣布“故障已解决”。crash loop 类问题往往是间歇性的有时候重启后十几分钟才再次崩溃。稳妥起见至少要持续观察日志文件 30 分钟以上确认增长曲线确实平稳了再收工。第三个坑是只用容量告警不看增长率。假如系统盘容量足够大日志风暴可能要跑几小时才触发容量告警届时空闲空间可能已经所剩无几了。更合理的方式是加上增长率监控例如记录一小时前后/var/log/syslog的大小差值一旦超过阈值就提前告警。6.3 一点个人体会经过这次折腾我现在面对磁盘告警时已经不会手忙脚乱了。整个过程的逻辑其实很简单先用df和du确认问题性质再用truncate而不是rm来争取恢复时间然后用日志统计命令锁定刷屏来源最后通过 journald 限额、logrotate 阈值、rsyslog 限流和监控告警把漏洞堵死。如果你也遇到服务器系统盘被 syslog 占满的告警不妨按这个流程走一遍。先别急着删文件想一想日志为什么会增长这么快把这个原因找到并解决掉才是真正意义上的“处理完成”。毕竟删日志只需要一秒而让系统不再被日志风暴击倒才是运维工作里最值得花时间的那部分。
返回列表