1. 问题现象与初步判断
那天凌晨2点37分,我正远程调试一个紧急项目,突然发现Coco Server服务不可用。登录服务器后看到控制台不断刷出"panic: write /var/log/coco/server.log: no space left on device"的错误信息。这种因为磁盘空间不足导致的服务崩溃,在运维生涯中其实并不罕见,但每次遇到都值得深入分析。
先看下这台服务器的基本情况:这是一台运行了3年多的老机器,系统盘是240GB的SATA固态,数据盘是4TB的机械硬盘。Coco Server作为核心业务系统,其日志默认存储在/var/log/coco目录下。通过df -h命令查看,发现根分区使用率已达100%,而/data挂载点还有1.2TB剩余空间。
关键提示:当服务突然崩溃时,第一个要检查的就是磁盘空间。我习惯用
df -hT命令,-T参数可以显示文件系统类型,这对排查很有帮助。
2. 磁盘空间分析实战
2.1 定位大文件
使用du -sh /* | sort -rh | head -10命令快速找出占用空间最大的目录。结果显示/var目录独占85GB空间,其中/var/log占了83GB。进一步分析发现:
/var/log/coco/server.log 42G /var/log/journal/ 38G /var/log/kern.log.1 2.1G这里暴露了两个问题:
- Coco Server的日志没有做轮转切割
- 系统journal日志长期堆积
2.2 日志系统原理剖析
Linux系统日志通常由以下组件构成:
- rsyslog:传统系统日志服务
- journald:systemd的日志系统
- 应用日志:如我们的Coco Server日志
journald采用二进制格式存储日志,默认配置下会占用最多10%的磁盘空间(在/var/log/journal目录)。但我们的情况显然超出了这个限制,说明配置可能被修改过。
3. 应急处理方案
3.1 立即释放空间
执行以下命令快速释放空间:
# 清空Coco Server日志 echo "" > /var/log/coco/server.log # 清理journal日志 journalctl --vacuum-size=200M # 删除旧内核日志 find /var/log -name "kern.log*" -mtime +30 -exec rm -f {} \;3.2 服务恢复
清理后需要重启服务:
systemctl restart coco-server但这时遇到了新问题 - 服务启动后立即崩溃,报错"panic: mmap failed"。这是因为Linux文件删除机制决定的:当文件被进程打开时,实际磁盘空间不会立即释放。
解决方案:
# 先停止服务 systemctl stop coco-server # 确认没有残留进程 ps aux | grep coco-server # 再次清理日志 rm -f /var/log/coco/server.log # 重新启动 systemctl start coco-server4. 长效解决方案
4.1 日志轮转配置
为Coco Server配置logrotate:
# /etc/logrotate.d/coco-server /var/log/coco/server.log { daily rotate 30 compress delaycompress missingok notifempty create 0640 coco coco postrotate systemctl reload coco-server >/dev/null 2>&1 || true endscript }关键参数说明:
- daily:每天轮转
- rotate 30:保留30个历史版本
- delaycompress:延迟压缩(方便问题排查)
- create:新建日志文件的权限和属主
4.2 Journald配置优化
编辑/etc/systemd/journald.conf:
[Journal] SystemMaxUse=1G RuntimeMaxUse=500M MaxRetentionSec=1month执行systemctl restart systemd-journald使配置生效。
4.3 监控告警设置
配置Prometheus监控规则:
- alert: DiskSpaceCritical expr: 100 - (node_filesystem_avail_bytes{mountpoint="/"} * 100 / node_filesystem_size_bytes{mountpoint="/"}) > 90 for: 5m labels: severity: critical annotations: summary: "Disk space is running out (instance {{ $labels.instance }})" description: "{{ $labels.mountpoint }} on {{ $labels.instance }} has only {{ $value | humanize }}% free space left"5. 深度排查技巧
5.1 查找被删除但仍占空间的文件
lsof +L1这个命令会列出所有链接计数为0但仍被进程打开的文件(即已删除但未释放空间的文件)。
5.2 使用ncdu进行可视化分析
安装ncdu工具:
apt install ncdu -y运行分析:
ncdu /var这个工具会以交互式界面显示磁盘使用情况,比传统的du命令更直观。
5.3 检查inode使用情况
有时候磁盘空间足够但inode耗尽也会导致类似问题:
df -i如果发现某个分区inode使用率接近100%,需要清理小文件:
# 查找包含大量文件的目录 find / -xdev -type f | cut -d "/" -f 2 | sort | uniq -c | sort -n6. 进阶防护方案
6.1 使用LVM动态扩容
如果服务器使用LVM管理磁盘,可以在空间不足时动态扩容:
# 查看当前VG空间 vgs # 扩展LV lvextend -L +50G /dev/mapper/vg-root # 调整文件系统 resize2fs /dev/mapper/vg-root6.2 日志分级存储
对于日志量大的系统,建议采用分级存储策略:
- 热数据:最近3天日志,保留在本地SSD
- 温数据:3天到1个月日志,存储在本地HDD
- 冷数据:1个月以上日志,归档到对象存储
可以使用logstash或fluentd实现自动化日志流转。
6.3 容器化部署方案
如果是容器化部署,需要特别注意:
- 配置合理的日志驱动(如json-file with size限制)
- 设置容器存储限制
- 使用sidecar容器处理日志
示例docker-compose配置:
services: coco-server: image: coco/server:latest logging: driver: "json-file" options: max-size: "100m" max-file: "5"7. 故障复盘与经验总结
这次事故教会我几个重要经验:
监控不能只关注服务状态:除了服务是否运行,还要监控其依赖资源(磁盘、内存、网络等)。我现在会在所有服务器上部署node_exporter,监控包括磁盘在内的各项指标。
日志管理是系统工程:不能只解决眼前问题。我后来为团队制定了日志规范:
- 所有应用必须支持日志轮转
- 生产环境禁止使用debug级别日志
- 日志格式统一采用JSON
- 重要日志需要异地备份
应急预案要常备:现在我的工具箱里永远备着这些命令:
# 快速释放空间三板斧 find /var/log -type f -name "*.log" -size +100M -exec truncate -s 0 {} \; journalctl --vacuum-time=1d docker system prune -af测试环境的真实性:这次问题在测试环境没出现,因为测试环境的日志量远小于生产环境。现在我会在测试环境模拟生产流量,提前发现问题。
最后分享一个实用技巧:当你想清理日志但又担心影响正在运行的服务时,可以使用truncate命令而非直接删除:
truncate -s 0 /var/log/large.log这样文件描述符保持不变,服务不会异常,同时立即释放磁盘空间。