Spring Boot 日志把云服务器磁盘写满了:Logback 滚动策略与日志轮转实战
一、故障现象:服务突然访问不了,重启也不行
一台 Flexus 云服务器上跑着一个 Spring Boot 应用,JAR 包直接启动,内嵌 Tomcat 监听 8080 端口,前面再挂一层 Nginx 反向代理。某天早上服务突然访问不了,登录服务器重启应用,发现应用根本起不来,控制台提示磁盘空间不足。
当时第一反应是磁盘被业务数据占满了,但这台服务器只跑了这一个应用,没有数据库、没有大文件。真正的原因查出来后,才发现是日志把磁盘写满了。
二、定位:三条命令找到罪魁祸首
第一步,看整体用量。
df -h
根分区 / 的使用率已经到了 100%,可用空间为 0。磁盘满了之后,不光应用起不来,系统写临时文件、写新的日志都会失败。
第二步,逐层下钻找大目录。
du -sh /* | sort -rh | head -5
结果指向了应用日志所在的目录。
第三步,看目录里最大的文件。
du -sh /opt/app/logs/* | sort -rh | head -5
ls -lh /opt/app/logs/
一个 app.log 就占了几十 GB。日志文件从应用上线那天起就没有清理过,一直在同一个文件里追加。
这里有一个容易踩的坑:日志文件正在被应用进程占用时,直接 rm 删除并不会释放磁盘空间,因为文件句柄还被进程持有,删除后空间依然被占用。应急处理要清空文件内容而不是删除文件:
truncate -s 0 /opt/app/logs/app.log
或者重启应用,让进程释放旧句柄。
三、根因:Spring Boot 默认日志没有滚动
Spring Boot 默认使用 Logback,默认配置只往一个文件里写,不做滚动、不做删除。只要应用长期运行,日志只会越写越大。
加速写满的因素通常有三个:
- 日志级别开得太低,生产环境还开着 DEBUG,框架内部日志海量输出;
- 定时任务、健康检查每隔几秒就打一条日志,日积月累非常可观;
- 某个接口的异常被反复捕获又反复打印堆栈,一条异常能打几十行。
磁盘空间是有限的,日志无限增长,写满只是时间问题。
四、根治:Logback 按大小加时间滚动
正确的做法是让日志按天和大小自动滚动,并设置总容量上限。logback-spring.xml 的关键配置:
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/opt/app/logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/opt/app/logs/app.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>50MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
几个参数的含义:
maxFileSize:单个文件超过 50MB 就滚动出一个新文件;maxHistory:只保留最近 30 天的归档日志,更早的自动删除;totalSizeCap:所有归档日志加起来不超过 3GB,超过就从最老的开始删,这是防止写满磁盘的最后一道闸。
同时把生产环境的日志级别收紧到 INFO,只保留必要的业务日志,DEBUG 只在排查问题时临时开启。
五、第二道防线:系统级 logrotate
对于不走 Logback 的日志,比如 Nginx 的访问日志、应用的启动脚本输出,可以用系统自带的 logrotate 做兜底。在 /etc/logrotate.d/app 里写:
/opt/app/logs/*.log {
daily
rotate 14
compress
missingok
notifempty
copytruncate
}
copytruncate 的作用是先复制再清空原文件,避免正在写日志的进程持有旧文件句柄导致空间不释放。
六、验证:改完要确认真的生效
配置改完重新打包部署后,验证三件事:
ls -lh看日志目录,确认出现了按日期滚动的新文件;df -h看根分区使用率回落到正常范围;- 故意把
maxFileSize临时设小一点,跑一段时间,确认日志确实会滚动、旧文件确实会被删除。没有验证的配置等于没有配置。
七、预防:磁盘用量要纳入日常巡检
- 每周看一次
df -h,或者配一个定时任务把磁盘用量打到巡检表里; - 云服务器磁盘使用率告警阈值设在 80%,用到 85% 就处理,不要等到 100% 再抢修;
- 日志级别、滚动策略写进部署清单,新服务上线时顺带检查一遍。
小结
日志写满磁盘的故障,表面看是磁盘不够,根子是日志没有生命周期管理。应急时用 truncate 清空被占用的日志文件先恢复服务,根治靠 Logback 的大小加时间滚动策略配上 totalSizeCap 上限,再用 logrotate 和磁盘告警做两道防线。把这三层做齐,同样的故障就不会再来第二次。
- 点赞
- 收藏
- 关注作者
评论(0)