☰
Linux日志管理实战:journalctl、logrotate与磁盘清理指南
2026/10/11 19:18:08 网站建设 项目流程

各位折腾 Linux 的朋友,不知道你们有没有遇到过这种场景:磁盘告警了,一顿排查下来发现/var/log占了好几个 G,甚至把根分区直接塞满;或者排障的时候想找某个服务的日志,结果发现关键时间点的记录早就被覆盖得干干净净;还有一种更头疼的,日志文件明明还在,但du和df看到的结果完全对不上。

这些问题的根源,都指向同一个东西——日志管理。

我很久之前一直觉得日志嘛,不就是程序把内容往文件里一写,完事了。直到有次生产环境出问题,我需要靠日志定位故障点,结果发现日志被轮转覆盖、裁剪得面目全非,那一刻我意识到日志管理是一项需要系统性对待的工程。这篇学习日志,我就把我在 Linux 下折腾日志管理的完整思路、实操过程和踩坑记录整理出来,从日志分类、核心工具原理,到日志轮转配置、磁盘空间释放技巧,再到常见故障排查,一次性讲清楚。

1. 日志体系全景:Linux到底在记录什么

1.1 日志不是日志文件那么简单

很多人在接触 Linux 日志时,第一反应就是“日志 = 文本文件”,这个理解不能算错,但太片面了。

在 Linux 系统里,日志的产生和存储路径大致分两派:一派是传统 syslog 体系,把各类程序运行信息通过 syslog 接口统一交给rsyslogd服务,再由它按照规则分发到/var/log下的不同文件;另一派是 systemd 引入的 journal 体系,由systemd-journald把内核、服务、启动过程等信息集中记录,日志以二进制格式持久化在/var/log/journal里。

这里有个关键点:journal 和 syslog 并不是互斥的,很多发行版上它们同时在工作。journald 负责收,rsyslog 也在收,然后各写各的。所以你会看到/var/log/messages里有内容,journalctl里也有内容,但两者可能略有差异。这个差异不是 bug,而是两条采集链路导致的正常现象。

但这还没完。应用程序自己还会打日志,比如 Nginx 的 access log 和 error log、应用框架自己写的业务日志、Java 应用的 GC 日志、数据库的慢查询日志等。这些日志有的走 syslog,有的是直接写文件,有的两者兼顾。所以日志管理要面对的是一个混搭生态,不是单一工具能全覆盖的。

理解了这一点,你就能明白为什么日志管理方案需要组合拳:journalctl 管 systemd 日志,rsyslog 管传统 syslog 日志收集,logrotate 管所有日志文件的轮转压缩,第三方工具管应用自身日志采集。

1.2 日志文件的分类与存放路径

我手动梳理了一下 Linux 系统里常见的日志文件和它们的用途,整理成了一张速查表,方便对照查看:

日志文件路径主要记录内容重要程度
/var/log/messages系统级通用日志,很多服务的运行信息都会记录在这里高
/var/log/syslog与 messages 类似,Debian/Ubuntu 系常用高
/var/log/secure认证与安全相关日志,包括登录尝试、sudo 操作高
/var/log/auth.log认证日志,Debian/Ubuntu 系对应 secure高
/var/log/boot.log系统启动过程日志中
/var/log/dmesg内核环形缓冲区日志,硬件驱动信息中
/var/log/croncrontab 计划任务执行日志中
/var/log/nginx/access.logNginx 访问日志,不属于系统日志,是应用自建中
/var/log/nginx/error.logNginx 错误日志中
/var/log/journal/systemd-journald 的二进制日志库高

这只是最基础的清单,每台机器实际内容会因安装的服务不同而不同。我建议你拿到一台新服务器之后,第一件事就是ls -alh /var/log/看看整体大小和文件分布,做到心里有数。

这里我想多说一句/var/log/dmesg。你可能听说过dmesg命令,它用来查看内核环形缓冲区的输出。其实/var/log/dmesg只是系统启动早期把 dmesg 内容保存下来的一个快照文件,它不会持续更新。真要排查内核级问题,要跑dmesg -T看实时缓冲,或者看 journal 里的 kernel 相关记录。

1.3 为什么不建议随手删日志

有一种观点我觉得需要纠正:日志可以删,但要用正确的方式删。

我见过有人排障空间不足时,直接rm -rf /var/log/messages,当场是释放了空间,但后患很多。大部分服务进程会一直持有着日志文件的文件句柄(file descriptor),你把文件rm掉了,进程还往那个句柄里写,数据照样写进磁盘,但你再也没有办法用常规方式读取或定位那个文件,空间也一直释放不了,必须重启进程才能真正释放。

更常见也更危险的情况是:日志文件是排障的唯一线索。你把日志删了,等于把案发现场给破坏了。尤其是安全审计、故障复盘这类场景,日志是根本依据,丢了就没法溯源。

所以正确做法是让日志轮转(log rotation),而不是直接删。本质上这是一个理念转变:日志管理追求的是按需保留、自动压缩、过期清理,而不是靠人肉去删。

2. 核心工具解析:journalctl、rsyslog 与 logrotate 三驾马车

2.1 journalctl:查看 systemd 日志的正确姿势

journalctl是 systemd 体系里最核心的日志查询工具。它的数据源是/var/log/journal目录下的二进制 journal 文件,而不是传统的文本日志。

我第一次用journalctl的时候,觉得这命令也太简单了,直接journalctl -xe就能看到最近的错误信息。但用得越深入越发现,这工具功能其实很强,只是很多人没用到位。

几个我日常频率很高的用法:

# 查看最近 30 分钟内的日志 journalctl --since "30 min ago" # 查看某个服务单元的日志 journalctl -u nginx.service # 查看指定时间段的日志 journalctl --since "2026-01-20 08:00:00" --until "2026-01-20 10:30:00" # 只看某个优先级以上的日志(0-7,数字越小越紧急) journalctl -p err # 跟随模式,类似 tail -f journalctl -f

这里我想特别讲一下优先级过滤。journal 日志每条都有一个 priority 字段,对应 syslog 的 emerg(0)、alert(1)、crit(2)、err(3)、warning(4)、notice(5)、info(6)、debug(7)。-p err会同时包含比 err 更严重的 emerg、alert、crit,相当于“看所有错误级以上的日志”。排查问题时这个参数能快速过滤掉大量无用信息,不要光看末尾 50 行就下结论。

还有一点值得一提:journalctl -xe里那个-x是显示解释信息,-e是跳到日志末尾。这俩组合起来就像“直接翻到账本最后一页看最近发生了什么”,应急排障时的效率非常高。

journald 的配置文件在/etc/systemd/journald.conf。默认情况下,日志存在内存还是磁盘,由Storage选项决定。默认值通常是auto,也就是“如果/var/log/journal存在就持久化,否则只写内存”。很多刚装好的系统并没有/var/log/journal目录,这意味着日志只在内存里,一旦重启,历史日志全部消失。如果你希望日志持久保留,务必执行:

mkdir -p /var/log/journal systemctl restart systemd-journald

2.2 rsyslog:传统日志的收集与转发中枢

rsyslog 作为 syslog 的增强版,承担着传统日志体系里收集、过滤、转发的核心角色。它的配置文件在/etc/rsyslog.conf,/etc/rsyslog.d/目录下面还能放分片的配置文件,实现模块化管理。

rsyslog 的配置逻辑可以理解为一个三要素模型:输入源 + 过滤条件 + 动作。

比如系统默认配置里这一行:

*.info;mail.none;authpriv.none;cron.none /var/log/messages

拆开看就是:所有 info 级别以上的日志,但排除 mail、authpriv、cron 这几类的日志,最终写入/var/log/messages。

如果我想把某个应用的日志单独收集到独立文件里,可以这样配置:

# /etc/rsyslog.d/myapp.conf if $programname == "myapp" then /var/log/myapp.log

保存配置后执行systemctl restart rsyslog,然后往 logger 里写一条测试消息:

logger -t myapp "This is a test log entry"

过两秒再去cat /var/log/myapp.log,应该能看到记录。

rsyslog 还承担着一个更重要的任务:日志转发。在多机环境下,把日志统一汇总到一台日志服务器上,是运维中的常规操作。配置方式是增加一个远程目标:

*.* @192.168.1.100:514

这个配置把所有日志通过 UDP 514 端口转发到 192.168.1.100。如果走 TCP,用两个@@:

*.* @@192.168.1.100:514

通常我会用 TCP 而不是 UDP,因为 TCP 有确认机制,日志不容易丢。日志转发在生产环境里价值很大,尤其是排查跨节点问题的时候,统一日志入口能省下大量来回切换机器的时间。

2.3 logrotate:让日志文件不爆盘的自动轮转机制

logrotate 是 Linux 下日志管理最重要的一个机制,基本没有之一。它的存在就是为了回答一个问题:日志文件越来越大怎么办?

logrotate 的工作原理不复杂:由一个 cron 任务(多数发行版放在/etc/cron.daily/logrotate)每天执行一次logrotate命令,根据配置决定哪些日志需要轮转、压缩、删除或重组。

核心配置路径有两个:全局配置/etc/logrotate.conf,以及分应用配置/etc/logrotate.d/目录下的各个文件。

来一段最典型的配置模板,我自己经常这么写:

# /etc/logrotate.d/myapp /var/log/myapp.log { daily rotate 7 compress delaycompress missingok notifempty copytruncate create 0644 root root }

逐项解释:

  • daily:按天轮转,当然还可以是weekly、monthly、hourly。
  • rotate 7:保留 7 个轮转后的旧日志文件。超过 7 份后最旧的会被删除。
  • compress:对轮转后的旧日志进行 gzip 压缩。
  • delaycompress:最新轮转出的一份暂不压缩,等到下一轮轮转时再压缩。为什么要加?因为有些程序还在往旧文件里写日志,立刻压缩可能导致内容丢失;拖延一个周期就安全很多。
  • missingok:日志文件不存在时不要报错,继续往下执行。
  • notifempty:日志文件为空时不触发轮转。
  • copytruncate:先复制一份当前内容到轮转文件,再把原文件截断。这个选项对有特定写日志行为的程序很重要,通常配合应用使用(比如 Apache、Tomcat)。
  • create:轮转后重新创建一个新的空日志文件,并设定权限。

这里我建议所有人在配置 logrotate 之前先运行一下检查和演练:

# 调试模式:查看执行过程但不真正执行 logrotate -d /etc/logrotate.conf # 强制执行(即使未到轮转周期) logrotate -f /etc/logrotate.conf # 仅对某个配置执行 logrotate -f /etc/logrotate.d/myapp

实际场景里有一个坑:copytruncate和create其实是两套策略,一般只用一种。copytruncate适合那些持续持有文件句柄的程序(比如 Nginx、Python 应用),因为它不改变原文件的 inode,只是把内容复制之后清空,程序写入不受影响。而create是直接把原文件改名成轮转文件,然后新建一个原名的文件,适合 syslog 这类会重新打开日志文件的服务。对大多数应用,我倾向于用copytruncate,因为它对应用写日志的影响最小,副作用是复制和截断之间存在极短的时间窗口,可能丢一点点日志,但对绝大多数场景可以接受。

3. 实操过程:从零搭建一套完整的日志管理方案

这一节我按照一个比较标准的实战流程来写,适合刚拿到一台 Linux 服务器、什么都不管先保证日志不失控的场景。整体分四步:查看现状 → 配置轮转 → 接入统一管理 → 定期巡检。

3.1 第一步:先搞清楚当前日志的占用情况

拿到服务器之后,第一件事是盘点日志资源占用。我一般会先跑这样一组命令:

# 查看 /var/log 目录所有文件及其大小,按块数排序 du -sh /var/log/* # 查看日志目录整体占用 du -sh /var/log # 查看磁盘分区占用 df -h # 查看哪些日志文件最大 find /var/log -type f -size +100M -exec ls -lh {} \;

这组命令能快速定位大头。有一回我检查某台业务服务器,发现/var/log/nginx/access.log已经 8.7G,就是业务量大了之后没人管轮转导致的。还有一次是/var/log/journal占用了 4 个 G,因为 journald 默认对日志大小没有做限制,系统跑了一年日志全留了下来。

如果只是应急排障,可以用tail或less去瞄一眼内容;但盘点大小,用du更靠谱。ls -lh看到的单个文件大小和du -h看到的可能有差异,这是因为du统计的是磁盘实际占用块,而ls显示的是文件逻辑长度,这在稀疏文件上体现得很明显。日志文件很少是稀疏文件,但总会有特殊情况。

3.2 第二步:配置 logrotate 轮转策略

盘点完成后,接下来就是给关键日志配置轮转策略。我建议的落地顺序是:先配置全局默认参数,再针对不同服务的日志配置个性化策略。

我的做法是维护一个配置规范:

日志类型轮转频率保留份数是否压缩是否 copytruncate
Nginx 访问日志daily14是是
应用业务日志daily30是是
系统 messagesweekly4是否
journal 日志按容量保留 500M不适用不适用

针对 Nginx 的配置比较典型,因为 Nginx 的 master 进程会保持日志文件的句柄不关闭,如果用默认的create方式,轮转后 Nginx 还会继续往旧文件(已改名的文件)里写日志,新文件永远不会被写入。必须用copytruncate或者用nginx -s reopen通知 Nginx 重新打开日志文件。

这是我要重点提醒的:logrotate 的 postrotate 脚本就是用来干这个的,配置里可以这样写:

/var/log/nginx/*.log { daily rotate 14 compress delaycompress missingok notifempty sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript }

kill -USR1是 Nginx 专门用来重新打开日志文件的信号。这个操作比copytruncate更干净,不丢日志,也是官方推荐的方式。

对于 Java 应用、Tomcat、Python 程序这类不好发信号重新打开文件的场景,用copytruncate更合适,因为它不需要程序配合,直接复制+截断,程序无感知。

3.3 第三步:将关键应用日志接入统一管理

如果应用本身就是写文本日志的,你只需要做好两点控制:写到哪里、轮转规则是什么。但如果你用的是 systemd 管理的服务,还可以让应用的 stdout 日志直接汇入 journal,然后用journalctl统一查询。

systemd 服务里只要不配置StandardOutput=,默认 stdout 就会进入 journal。这意味着你systemctl start myapp之后,journalctl -u myapp.service就能看到服务的所有输出。

这种模式的优点是日志采集完全自动,不需要应用依赖 log4j 这类框架做文件输出配置。缺点也明显:如果 journal 本身不持久化,重启就丢。

所以我建议的落地方案是混合模式:

  1. 对所有 systemd 服务,确认 journal 持久化已开启。
  2. 对需要长期保存或者要转给日志平台的关键业务日志,应用自己写文件,同时用 logrotate 控制轮转。
  3. 对系统级日志,保留 syslog 体系,确保/var/log/messages、/var/log/secure这些常规文件持续有数据。

这样做的原因很实际:日志查询工具链里,journalctl对单个 unit 的过滤很便利;但做跨主机采集、接入第三方日志平台时,绝大多数时候还是基于文件路径去采集的,journal 的二进制格式接入成本高。所以保留 syslog 文件和日志平台的兼容性是我们必须留的后路。

3.4 第四步:定时巡检与日志分析

配置完成后,日志管理不能一劳永逸。我见过太多例子:配置了 logrotate,但 sh 脚本路径不对、权限不对,结果轮转从来没正常执行过。

日志管理方案的落地最后一步是巡检机制的建立。可以用简单的方式:

# 手动执行一次轮转看有没有报错 logrotate -f /etc/logrotate.conf # 查看 logrotate 是否有执行记录 cat /var/log/logrotate.log 2>/dev/null || true # 查看系统 cron 日志里 logrotate 是否有执行 grep logrotate /var/cron/log 2>/dev/null || grep logrotate /var/log/cron

如果发现 logrotate 没有执行,最常见的原因是:配置文件里路径写错了、权限不足、/etc/cron.daily里的脚本没有可执行权限。把这三项逐个排除掉,大部分问题都能解决。

我还习惯把日志分析做成一个每日简短的检查脚本,比如统计访问量前 10 的 IP、错误日志出现频率等。这个环节能让你真正做到“主动发现问题”,而不是等告警响了再被动应对。举一个最基础的例子:

# 统计今天的异常 HTTP 状态码 awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

日志管理其实是可以和日常巡检、容量规划联动起来的。日志增长速度决定了磁盘扩容的节奏,这一步做好了,运维就稳了一大半。

4. 常见问题与排查技巧实录

这一节来聊聊我在日志管理实操中遇到的典型问题,每一条都是实际踩过的坑。

4.1 日志文件删除后空间不释放

这是新手最容易碰到的问题,我也栽过一次。现象是:du -sh /var/log/messages显示文件大小只有几 K,但df -h看根分区依然爆满。

原因就是之前说的文件句柄问题:某个服务进程(比如 rsyslogd)一直持有着被删除的文件句柄,文件虽然从目录里看不到了,但在磁盘上依然有对应空间占用,只是没有文件名了。

排查方法:

# 找出持有已删除文件句柄的进程 lsof | grep deleted

输出里能看到类似这样的行:

rsyslogd 1234 root 12w REG 253,0 2147483648 123456 /var/log/messages (deleted)

这里的/var/log/messages (deleted)说明这个文件被 rsyslogd 打开后又被删除了,但进程还在写它。

解决思路有几个,从轻到重:

  1. 通过kill -HUP <pid>或systemctl restart rsyslog让服务重新打开日志文件,最安全优雅。
  2. 如果是临时文件,可以直接重启对应服务。
  3. 实在无法重启服务的情况下,可以考虑复制/proc/<pid>/fd/12的内容到原路径下,但操作风险高,不推荐新手尝试。

这类问题最好的防备就是不要直接rm日志文件,让 logrotate 处理。

4.2 journal 日志疯狂膨胀

journald 的日志默认不限制大小,如果你开了持久化,时间久了磁盘空间会被慢慢吃掉。这个问题在我当时配置日志管理时最先暴露出来。

journald 的配置里有两个关键参数:

SystemMaxUse=1G SystemMaxFileSize=200M

SystemMaxUse指定 journal 持久化日志总容量的上限,SystemMaxFileSize指定单个 journal 文件的最大大小。生产环境里我建议强制设置这两个值,免得日志把磁盘搞挂。

配置完要重启 journald 并清理旧日志:

systemctl restart systemd-journald # 清理 journal 日志到 500M 大小 journalctl --vacuum-size=500M # 清理超过 7 天的日志 journalctl --vacuum-time=7d

--vacuum-size和--vacuum-time是清理 journal 的工具。这两个参数可以按需混用。注意:这俩参数是直接清理,没有恢复选项,用之前一定确认数据不再需要。

还有个小细节:journalctl --vacuum-size=500M并不是刚好把总量减到 500M,而是会尽量逼近这个目标。执行完用journalctl --disk-usage查看当前占用。

4.3 日志时间不同步导致排障困难

这个问题应该被列进日志管理的隐藏坑。如果系统时间和日志采集时间不一致,排障时很难对齐时间线。

我处理过一起案例:某系统日志记录的时间和实际业务异常发生时间差了 8 个多小时,排查时如果没有换算时区,很容易被误导。

实际情况是,服务器时区没设置正确,或者当年经常遇到的系统时间漂移问题。日志写入的都是系统当前时间,而系统时间错了,日志自然就错了。

所以日志管理的底层前提是时间同步。务必确认 NTP 或 chrony 服务正常运行:

# 查看当前时间 date # 查看时区设置 timedatectl # 查看时间同步服务状态 timedatectl status # 查看chrony服务同步状态 chronyc tracking

如果你用 journald,配好之后journalctl --utc可以统一用 UTC 输出时间,这在跨时区排障时非常有用。我自己在日志分析场景下习惯统一转成 UTC,避免不同机器时区不同导致的误判。

4.4 日志过多被内核限制

还有一个很容易被忽略的坑:/var/log所在文件系统的 inode 耗尽了。日志文件数量特别多、单个文件特别小的时候,磁盘可能还有空间,但 inode 用完了,导致所有新建文件直接失败,表现为“磁盘空间不足但df -h显示还有空间”。

这时候要跑df -i看 inode 使用率。如果 inode 满了,解决办法是删除无用的小文件,以及调整 logrotate 策略,把轮转旧文件的保留数量降低。

inode 的问题在日志量大的机器上出现概率其实挺高,因为大量日志文件都是小文件,比如 cron 的轮转文件、journal 的分片文件。所以检查日志管理方案时,一定要把 inode 检查纳入常规巡检项。

5. 日志管理方案的进阶心得与最终建议

日志管理做到基础轮转和统一查看,只能算及格。要做得好,还需要思考几个更深入的点。

第一,日志不是你自己的私有财产。你的服务器出了故障,如果日志分散在一台台机器里,别人(同事、下游团队、甚至是未来的自己)去排障时,唯一的路径就是逐台登录、逐个路径翻找。我强烈建议至少在关键节点做统一的日志聚集,哪怕是简单地把关键日志 push 到同一台日志服务器。之后再进阶到日志平台(如 ELK 这类开源方案),也只是在收集端做扩展而已。

第二,日志保留策略没有万能模板。开发环境的日志可以只留 3 天,生产环境的重要业务日志至少要留 30 天,安全类日志建议留 90 天甚至更长,审计要求严格的环境可能要按年度归档。保留时长必须和业务合规、排障需求对齐,不要一味为了省空间把日志时间缩得很短。我的习惯是先规定最低保留要求,再通过容量评估确定磁盘规划。

第三,轮转配置完成后一定要验证。配置完 logrotate 不验证等于白配。我自己的验证步骤很简单:查看/var/lib/logrotate/status文件,看轮转是否在按预期时间执行;再配合跑一次logrotate -f观察日志是否真的生成了轮转文件。

第四,日志内容本身的质量也很关键。程序里输出的日志信息过于随意(比如全部打print)会导致日志量大但信息密度低。从这个角度来看,日志管理和程序开发是联动的:日志级别要不要分级、关键路径要不要打点、报错时要不要带上下文参数,这些设计层面的问题,在日志管理方案里也要提前想清楚。基础日志框架里常见的 info/error/debug 分级就是为此服务的。

以我个人的操作为例,日志管理方案不是一步到位的。我起初只配置了 logrotate,保证磁盘不爆;后来加了 journal 持久化并设置了容量上限;再后来又整理了 syslog 转发,把多台机器的日志归拢到一处。每一步都是被实际故障逼出来的。这里我给所有刚开始做日志管理的朋友一句真心话:宁可前期多花一点时间把日志目录、轮转策略、保留周期、巡检项目写清楚,也不要等出事了再去翻日志,那时候你会后悔当初为什么偷懒。

有一个小技巧可以分享给大家:给/etc/logrotate.d/目录下的每个配置文件都写清注释,注明这个轮转策略针对什么服务、为什么用这个保留周期、是否有 postrotate 脚本以及它的作用。过几个月回头看这些配置,你会庆幸当时留了说明。另一个是别忘记定期ls -alh /var/log/扫一眼,日志文件的增长趋势是系统健康的晴雨表,观察多了你自然会对“正常增长”和“异常膨胀”产生直觉。

这就是我这次日志管理学习的全部内容了。日志管理看似是运维里最不起眼的一环,但它直接决定了系统出问题时你还有没有“现场还原”的能力。把这件事做扎实,比用再花哨的监控工具都管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询