凌晨3点,服务器突然报警:磁盘100%!
你连上服务器一看——不是数据库,不是程序,而是一个不起眼的文件:
access.log,已经飙到 80G。
这一刻你才明白:
日志不轮转,迟早把服务器拖死。
而不少的运维事故,其实都不是系统崩了,而是——
日志把磁盘吃光了。
日志是排查问题的关键,但如果不加以管理,就会从“帮手”变成“隐患”。而Linux自带的logrotate工具,正是解决Linux日志切割、日志占满磁盘的“神器”——它能自动实现日志的切割、压缩、保留、清理,全程无需人工干预,让日志管理变得高效又省心。
本文将从“事故场景→危害分析→原理讲解→参数详解→实战配置→调试排错→避坑总结”,循序渐进讲解logrotate的使用方法,结合logrotate配置教程,覆盖nginx日志轮转、mysql日志切割等高频场景,无论是初学者还是有经验的运维,都能看完就会用,彻底解决日志占满磁盘问题,掌握日志占满磁盘解决方案。
一、日志不切割的3大致命危害
在讲解logrotate之前,先明确一个核心问题:为什么必须做日志轮转?日志不切割,带来的后果远比你想象的严重,尤其是生产环境。
- 磁盘被占满,服务直接崩溃:这是最常见的问题。比如nginx的access.log,在高并发场景下,一天就能产生几十G日志,若不切割,用不了几天就会占满磁盘。磁盘满了之后,服务无法写入新日志、数据库无法写入数据,甚至系统无法正常启动,造成业务中断。
- 日志文件过大,无法查看和分析:当日志文件达到几十G、上百G时,用
cat、tail等命令查看会异常缓慢,甚至直接卡死;若需要排查历史问题,打开日志文件都要花费大量时间,严重影响排错效率。 - 浪费磁盘空间,增加存储成本:未压缩的日志文件占用大量磁盘空间,尤其是长期保留的日志,会导致磁盘资源浪费,若使用云服务器,还会增加存储费用。
而logrotate的核心作用,就是通过“自动切割、压缩、清理”,彻底解决以上问题,让日志管理自动化、规范化。
二、logrotate 工作原理
很多初学者觉得logrotate很复杂,其实核心原理非常简单,用一句话就能概括:logrotate通过定时任务(crond)触发,读取配置文件中的规则,对符合条件的日志文件进行切割、压缩、保留,同时生成新的空日志文件,确保服务正常写入日志。
具体工作流程拆解(以每天切割一次为例):
- 系统默认的定时任务(
/etc/cron.daily/logrotate)会在每天固定时间(通常是凌晨3点左右)执行logrotate; - logrotate读取主配置文件(
/etc/logrotate.conf)和应用专属配置(/etc/logrotate.d/目录下的文件); - 根据配置中的规则(比如日志大小、时间),检查日志文件是否需要切割;
- 若满足切割条件,会将当前日志文件重命名(比如
access.log→access.log.1),然后生成新的空access.log,供服务继续写入; - 对旧日志进行压缩(可选),并按配置保留指定份数的旧日志,超过份数的自动删除;
关键补充:logrotate的配置采用“主配置+子配置”的结构,主配置(/etc/logrotate.conf)定义全局规则,子配置(/etc/logrotate.d/下的文件)定义单个应用(如nginx、mysql)的专属规则,子配置会覆盖主配置的全局规则,这样的设计更灵活,便于针对不同应用单独配置,也是生产环境中最常用的配置方式。
另外需要注意:logrotate本身不具备定时功能,完全依赖系统的crond定时任务触发,这也是很多初学者容易误解的点——如果crond服务未启动,logrotate将无法自动执行。
logrotate 核心5步模型:
触发 → 判断 → 切割 → 压缩 → 清理
一句话记住:
定时触发看条件, 满足规则就切割, 旧日志压缩归档, 超出数量自动删。
三、logrotate 核心配置文件与参数详解
要熟练使用logrotate,首先要掌握它的配置文件结构和常用参数——这是实战配置的基础,每个参数都对应一个具体的日志管理规则,下面结合实例,逐一讲解最常用、最实用的参数,同时补充容易忽略的细节,打造一份实用的logrotate配置教程。
3.1 核心配置文件结构
logrotate的配置文件主要分为两类,二者配合使用,优先级有明确区分:
| | |
|---|
| | |
| 应用专属子配置目录,每个应用一个配置文件(如nginx、mysql) | |
主配置文件(/etc/logrotate.conf)默认内容(简化版,注释已精简,适配CentOS/Ubuntu通用):
# 全局默认保留4份旧日志
rotate 4
# 每周轮转一次(默认规则,可被子配置覆盖)
weekly
# 压缩旧日志(默认开启,可关闭)
compress
# 日志为空时,不执行轮转
notifempty
# 日志不存在时,不报错
missingok
# 延迟压缩(下次轮转时再压缩上一次的旧日志)
delaycompress
# 轮转后,重启指定服务(确保服务继续写入新日志)
postrotate
/bin/systemctl reload rsyslog.service > /dev/null 2>&1 || true
endscript
3.2 常用配置参数详解
以下是logrotate最常用的配置参数,每个参数都包含“作用+示例”,通俗易懂,新手可直接套用,同时补充实战中常用的进阶参数:
| | |
|---|
| | rotate 7 |
| 按时间轮转:daily(每天)、weekly(每周)、monthly(每月) | daily |
| 按日志大小轮转,达到指定大小后触发切割(优先级高于时间轮转) | size 100M |
| | compress |
| 延迟压缩:本次轮转不压缩,下次轮转时再压缩上一次的旧日志(避免压缩时影响服务写入) | delaycompress |
| 覆盖delaycompress,轮转时立即压缩旧日志(适合日志写入频率低的场景) | nodelaycompress |
| | nocompress |
| 当日志文件不存在时,不报错,继续执行其他日志的轮转 | missingok |
| | notifempty |
| 轮转后,生成新的空日志文件,并指定权限、所有者和所属组(避免服务无法写入) | create 0644 root root |
| 轮转完成后,执行一段shell命令(最常用:重启服务,确保服务写入新日志) | |
| 给旧日志添加日期后缀(如access.log-20240520),便于区分时间 | dateext |
关键提示1:参数的优先级是「size」>「时间(daily/weekly/monthly)」,即如果同时配置了size 100M和daily,只要日志达到100M,就会立即触发轮转,不管是否到了每天的轮转时间。
关键提示2:postrotate脚本如果执行失败,会导致服务无法重新打开新日志,进而无法写入日志,可通过查看/var/log/messages系统日志排查具体错误原因。
通用最小可用配置(新手直接用):很多新手看完参数还是不会写,这份最小配置可直接套用,适配大多数简单场景:
# 通用日志轮转最小配置(新手直接复制)
/var/log/*.log {
daily
rotate 7
compress
missingok
notifempty
create 0644 root root
}
四、生产级场景实战配置
4.1 场景 1:为 Nginx 配置日志轮转
Nginx 日志通常分为 access.log(访问日志)和 error.log(错误日志),默认路径为 /var/log/nginx/,以下配置适配 CentOS/Ubuntu 官方安装路径,包含平滑重载、日期后缀等生产级优化。
实操步骤
- 创建 Nginx 专属配置文件
sudo vim /etc/logrotate.d/nginx
- 写入以下配置
# Nginx 日志轮转生产级配置
/var/log/nginx/*.log {
daily # 按天轮转
rotate 7 # 保留 7 份历史日志
size 50M # 额外条件:日志达 50M 立即轮转(优先级高于 daily)
compress # 自动压缩旧日志
delaycompress # 延迟压缩(避免影响 Nginx 写入)
missingok # 日志不存在不报错
notifempty # 日志为空不轮转
create 0644 nginx nginx # 新日志权限 0644,所有者 nginx:nginx
sharedscripts # 所有日志轮转完成后,只执行一次重载
postrotate # 轮转后平滑重载 Nginx(官方推荐方式)
# 兼容不同启动方式,避免 reload 失败
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid) > /dev/null 2>&1 || true
else
/bin/systemctl reload nginx.service > /dev/null 2>&1 || true
fi
endscript
dateext # 旧日志添加日期后缀(如 access.log-20240520)
dateformat .%Y%m%d # 日期格式:年月日
}
关键参数通俗解释
| |
|---|
| Nginx 官方推荐的日志切换信号,仅重新打开日志文件,不中断服务,比systemctl reload更轻量 |
| 避免 access.log 和 error.log 分别轮转时,重复执行两次 Nginx 重载 |
| 旧日志文件名带日期,方便按时间溯源,替代默认的.1、.2序号 |
4.2 场景 2:为 MySQL 配置日志轮转
MySQL 日志主要有 error.log(错误日志)、slow.log(慢查询日志),默认路径为 /var/log/mysql/(部分系统为 /var/lib/mysql/),以下配置兼顾安全性与兼容性。
实操步骤
- 创建 MySQL 专属配置文件
sudo vim /etc/logrotate.d/mysql
- 写入以下配置(根据实际日志路径修改)
# MySQL 日志轮转生产级配置
/var/log/mysql/*.log {
weekly # 按周转轮(MySQL 日志增长较慢)
rotate 4 # 保留 4 份(约 1 个月)
size 100M # 日志达 100M 立即轮转
compress
delaycompress
missingok
notifempty
create 0640 mysql mysql # MySQL 日志权限需为 0640,避免权限泄露
sharedscripts
postrotate # 轮转后刷新 MySQL 日志(无需重启)
# ⚠️ 不要在配置中明文写密码!推荐用 mysql_config_editor 配置免密登录
/usr/bin/mysqladmin flush-logs > /dev/null 2>&1 || true
endscript
dateext
dateformat .%Y%m%d
}
安全警告
⚠️ 绝对不要在配置文件中明文写数据库密码! 原因:logrotate 配置文件可能被低权限用户读取,导致密码泄露。
推荐方案:
- 使用
mysql_config_editor 配置免密登录(生产环境首选):mysql_config_editor set --login-path=client --user=root --password
注意事项
- 若 MySQL 日志路径为
/var/lib/mysql/,需修改配置路径,并确保 logrotate 有该目录的读取权限(可执行 sudo chmod 755 /var/lib/mysql/); - MySQL 二进制日志(binlog)无需配置 logrotate,MySQL 自身会自动轮转。
4.3 场景 3:为自定义脚本日志配置轮转
日常运维中,我们自己编写的备份脚本、监控脚本也会生成日志,以备份脚本日志 /var/log/backup.log 为例,配置如下:
实操步骤
- 创建自定义脚本日志配置文件
sudo vim /etc/logrotate.d/custom-backup
- 写入以下配置(通用型,可直接修改路径套用)
# 自定义备份脚本日志轮转配置
/var/log/backup.log {
daily # 按天轮转
rotate 3 # 保留 3 份
size 10M # 日志达 10M 立即轮转
compress
missingok
notifempty
create 0644 root root # 自定义日志所有者为 root
postrotate # 无需重启脚本,生成新日志后自动写入
echo "日志轮转完成:$(date '+%Y-%m-%d %H:%M:%S')" >> /var/log/backup.log
endscript
dateext
# 可选:指定旧日志存放目录(需提前创建)
# olddir /var/log/backup/old
}
关键提示
- 自定义脚本日志通常无需重启服务,配置
create 参数生成新空日志后,脚本会自动写入新文件; - 若脚本仍写入旧日志,可在
postrotate 中添加重启脚本的命令(如 systemctl restart backup.service)。
五、手动触发日志轮转与调试方法
配置完成后,无需等待定时任务,可手动触发验证配置;若出错,也可通过调试模式快速定位问题。
5.1 手动触发日志轮转
| | |
|---|
| sudo logrotate /etc/logrotate.conf | |
| 强制触发指定配置(测试用) | sudo logrotate -f /etc/logrotate.d/nginx | |
| sudo logrotate -vf /etc/logrotate.d/nginx | |
| cat /var/lib/logrotate/status | |
验证是否成功
执行强制触发后,去日志目录查看:
ls -l /var/log/nginx/
若出现 access.log-20240520.gz(压缩后的旧日志)和新的空 access.log,说明轮转成功。
5.2 调试模式(排查配置错误)
若手动触发后日志未正常轮转,使用调试模式查看具体错误(不实际执行轮转,仅输出调试信息):
# 调试 Nginx 配置,不实际执行
sudo logrotate -d /etc/logrotate.d/nginx
常见错误及排查方法
| | |
|---|
| | 修改权限:sudo chmod 644 /etc/logrotate.d/nginx,或检查日志目录权限 |
| | 临时注释notifempty,或等待日志生成后再测试 |
| postrotate | 手动执行该命令(如systemctl reload nginx),确认能正常运行后修改配置 |
| error: stat of ... failed | | 核对实际日志路径(可用find / -name "error.log"查找)并修改配置 |
六、常见问题与避坑指南
在实际使用中,新手很容易遇到各种问题,这里总结5个最常见的坑,以及对应的解决方法,结合搜索到的实战经验,帮你少走弯路。
问题1:配置后,日志没有自动轮转
- 原因1:定时任务(
/etc/cron.daily/logrotate)未执行,或执行时间未到; - 解决1:手动触发
logrotate /etc/logrotate.conf,若能正常轮转,说明配置没问题,等待定时任务即可;若手动也无法轮转,排查配置错误。 - 原因2:日志文件未达到轮转条件(比如配置了
size 100M,但日志只有50M,且未到时间); - 解决2:用
logrotate -f强制触发,或修改size参数,降低触发阈值。 - 原因3:crond服务未启动,logrotate无法被定时触发;
- 解决3:启动crond服务(
systemctl start crond),并设置开机自启(systemctl enable crond)。
问题2:轮转后,服务无法写入新日志
- 原因1:新日志文件的权限、所有者配置错误,服务没有写入权限;
- 解决1:检查
create参数,确保权限、所有者与服务一致(如nginx用0644 nginx nginx,mysql用0640 mysql mysql),可手动修改日志权限测试(chmod 0644 /var/log/nginx/access.log)。 - 原因2:
postrotate中的重启服务命令错误,服务未重新加载,仍写入旧日志; - 解决2:手动执行
postrotate中的命令(如systemctl reload nginx),确认命令能正常执行,修改配置中的命令;若nginx用源码安装,需指定pid文件路径(如/usr/local/nginx/logs/nginx.pid)。
问题3:旧日志没有被压缩
- 原因1:未配置
compress参数,或配置了nocompress参数; - 解决1:在配置中添加
compress参数,删除nocompress。 - 原因2:开启了
delaycompress,本次轮转的旧日志会在下次轮转时压缩; - 解决2:要么等待下次轮转,要么关闭
delaycompress(不推荐,可能影响服务写入),或改用nodelaycompress参数(立即压缩)。
生产环境3个必踩坑(重点记):
如果你觉得本文对你有帮助,欢迎点赞、推荐、转发,关注我,后续会分享更多Linux入门干货!
文 / 零距技术仓
记录每一次真实的折腾 (#^.^#)
🚀 想看到更多实用折腾技巧?
👉 先关注
💬 评论区说说你的经历或想看的内容
👍 点赞表示支持
🔁 顺手分享给也在折腾的人,让大家都少踩坑 😎