我们平时排查服务器故障,第一件事就是翻日志。但你有没有想过,日志本身如果没人管,也会变成另一种“故障”——把磁盘塞满、把服务拖垮、关键时刻找不到有效信息。前段时间整理了一轮 Linux 日志管理的学习笔记,从系统日志体系、主流的 rsyslog 和 journald,到日志轮转、采集分析和一些实战排查技巧,把我觉得真正用得上的东西沉淀成了一篇完整的记录。这篇内容适合刚接触 Linux 运维的初学者,也适合那些一直在用系统默认配置、但没深入理解过日志机制的朋友。
1. 日志体系的整体设计思路
很多初学者会把“日志管理”等同于“看日志”,其实两者差得很远。看日志是排查问题时的动作,管理日志则是一整套从产生、收集、存储、轮转、清理到分析的生命周期治理。一开始我也只看不管理,直到有一次某个服务疯狂打日志,把根分区写满,数据库直接挂掉,才老老实实从头学起。
1.1 核心需求解析:日志管理到底要解决什么问题
日志管理的核心需求可以拆成四个层面。
第一个层面是完整性。系统里每时每刻都在产生日志,内核消息、用户登录记录、服务运行状态、应用异常堆栈,散落在不同的地方。如果连日志都收不全,排障时就会像盲人摸象。第二个层面是可查询性。日志不仅要记下来,还得能在关键时刻快速找到需要的那一条。第三个层面是存储成本控制。日志会无限增长,磁盘空间是有限的,必须有一套自动清理的机制。第四个层面是安全性。日志里可能有关键业务数据、管理员操作记录,不能被随意篡改或丢失,需要做好权限控制,甚至考虑异地同步。
这四个需求放在一起,就能理解为什么现代 Linux 发行版普遍采用journald + rsyslog的双轨体系:journald 负责高性能采集和结构化存储,rsyslog 负责传统 syslog 协议兼容、远程转发和灵活过滤。
1.2 日志来源扫描:内核、服务、应用都在哪里留下痕迹
Linux 日志的来源大概能分成五类,排查问题时先从这些路径入手会比较有方向。
第一类是内核日志,由内核直接产出,通过dmesg可以查看。内核日志记录了硬件检测、驱动加载、文件系统错误、OOM 杀进程这类底层事件。比如磁盘出现 IO 错误、网卡链路抖动,都从这里看最直接。
第二类是系统服务日志,比如 cron 定时任务、systemd 管理的各个服务,它们的运行状态会被 systemd-journald 捕获。用journalctl -u 服务名就能查看特定服务的输出,这是排查 systemd 服务启动失败最快的手段。
第三类是登录日志,主要是/var/log/wtmp、/var/log/btmp、/var/log/lastlog。wtmp记录成功登录,btmp记录失败登录,lastlog记录每个用户最近一次登录时间。这些文件是二进制格式,必须用last、lastb、lastlog命令读取。
第四类是应用日志,由 nginx、MySQL、Java 应用等自己写到/var/log/或自定义目录。这些日志格式五花八门,通常也是排障中价值最高的部分。
第五类是安全审计日志,主要是/var/log/secure或/var/log/auth.log,记录了用户认证、sudo 授权、SSH 登录等安全相关事件。系统被人爆破时,这个日志是铁证。
把每个来源对应的命令和文件记住,排查问题时会节约大量时间。实际排查时不要漫无目的地翻文件,先想清楚问题可能出在哪一层,再定向去对应日志源里找。
1.3 架构选型:为什么现代系统偏爱“双轨并行”
早期 Linux 发行版只靠 syslog 体系,配置文件是/etc/syslog.conf或/etc/rsyslog.conf。syslog 是文本日志,规则简单,但没有结构化信息,检索靠 grep,而且不在内存中缓冲,写压力大时性能不佳。
systemd 普及之后,journald 被引入,它把日志以二进制格式存进/var/log/journal/,自动关联元数据(时间、进程号、用户、服务单元),还支持索引检索,速度远超文本 grep。但 journald 不是万能的,它缺少 syslog 那样的灵活转发规则,传统工具对二进制日志也水土不服。
所以主流发行版的策略是让两者配合:journald 作为前端采集器和结构化存储,同时把日志转发给 rsyslog,由 rsyslog 完成持久化落盘、远程转发和高阶过滤。这个架构每个角色只干自己最擅长的事,扩展性和稳定性都更好。
在我实际接触的环境中,CentOS 7 时代很多人把 rsyslog 关掉只留 journald,结果日志一多磁盘压力大,排查旧问题时 journald 日志清掉就找不回来了。我的建议是保留双轨,除非你能明确掌控日志落盘策略和清理周期。
2. 硬核实操:journald 的使用细节
journald 是 systemd 家族的核心组件之一,维护难度低,功能却很强大。不少人对它的认识停留在journalctl -xe这一条命令上,其实它值得更深入的使用。
2.1 journalctl 的高频查询姿势
日常排障中,journalctl的查询方式会直接影响效率。我整理了五类最常见的用法,基本覆盖了工作中绝大多数情况。
按服务过滤是最常用的:journalctl -u nginx.service只看某个服务的日志,加上-u可以用多个服务做交集或并集。按时间过滤也很常规,journalctl --since "2026-01-20 09:00:00" --until "2026-01-20 12:00:00"可以精确锁定故障时间段。配合-p按优先级过滤是定位问题最快的手段,比如journalctl -p err只看错误级以上的日志。实时跟踪用journalctl -f -u mysqld,类似 tail -f 的效果。查看内核日志用journalctl -k,等价于 dmesg 但显示更清晰。
这些命令可以组合使用。例如某次排查 MySQL 凌晨崩溃问题,我用的命令是:
journalctl -u mysqld.service --since "2026-01-20 02:00" --until "2026-01-20 02:30" -p warning一下子就筛出了崩溃前十几分钟的关键报错,效率远超翻整个日志文件。
2.2 journald 存储与性能参数调优
journald 的配置文件是/etc/systemd/journald.conf,里面有四个参数我最常调,分别是SystemMaxUse、SystemKeepFree、MaxRetentionSec、Compress。
SystemMaxUse控制 journald 最多使用多少磁盘空间,默认是分区大小的 10%,实际上经常偏大,生产环境我习惯显式设置为 500M 或 1G。SystemKeepFree表示要预留多少空间给其他应用,默认 15%,磁盘紧张时要调大。MaxRetentionSec按时间控制日志保留周期,配合 MaxUse 使用。Compress默认就是 yes,文本日志压缩率很高,可以大大节省空间。
我常用的配置片段:
[Journal] SystemMaxUse=1G SystemKeepFree=2G MaxRetentionSec=30day Compress=yes改完配置后执行systemctl restart systemd-journald生效。这里有个坑要注意:journald 重启或journalctl --vacuum-size=500M这类清理操作会删除旧日志,如有审计合规要求,需要提前把日志做异地备份或转发到远程日志服务器。
2.3 查看当前占用与主动清理策略
journald 日志目录在/var/log/journal/,可以用一条命令查看真实占用:
journalctl --disk-usage输出会显示当前日志占用空间和文件数。如果发现占用异常高,可以用三种清理方式。
journalctl --vacuum-size=500M是最常用的,把日志总量压到 500M 以内,保留新日志删除旧日志。journalctl --vacuum-time=7d按时间清理,7 天前的日志全部删掉。journalctl --vacuum-files=10保留最近 10 个日志文件。这三个命令可以组合使用,安全可靠,也是我最推荐的主动清理手段。
注意:执行 vacuum 操作前务必确认没有未保存的重要日志。我踩过一次坑,把某个测试环境的日志清了,结果发现调试信息也没了,白白多排查了一整天。生产环境谨慎操作,建议先在测试环境验证清理效果。
3. rsyslog 配置深度拆解
rsyslog 是传统 syslog 的增强版,配置文件在/etc/rsyslog.conf,规则目录在/etc/rsyslog.d/。它负责把 journald 转发来的日志按规则落盘,或者转发给远程日志服务器。学习 rsyslog 的核心就是学会理解“选择器(selector)”和“动作(action)”这两个概念。
3.1 选择器与日志优先级:facility 和 priority 的搭配
rsyslog 的选择器格式是“设施.优先级”,比如authpriv.*、mail.err。facility 表示日志来源类别,常见的有auth(认证,新系统多用 authpriv)、cron(计划任务)、daemon(系统守护进程)、kern(内核)、mail(邮件)、user(用户进程)。priority 表示严重级别,从高到低是emerg、alert、crit、err、warning、notice、info、debug。
规则里mail.*表示所有级别的邮件日志,mail.err表示错误及以上级别,*.info表示所有设施的 info 级以上日志,authpriv.none表示排除认证日志。这些规则从前往后匹配,同一个日志可能被多条规则命中从而写入多个文件,逻辑是这样的。
一个典型规则:
# /etc/rsyslog.d/example.conf cron.* /var/log/cron.log *.info;mail.none;authpriv.none;cron.none /var/log/messages authpriv.* /var/log/secure第二条规则排除了 mail、authpriv、cron,避免消息重复写入,这就是实际运维中避免日志重复的经典写法。
3.2 模板与落盘规则:把日志按需求归类
只按默认规则落盘往往不够,比如希望把某业务的日志单独存一份,方便按业务维度排查,这就用到了 rsyslog 的模板功能。
创建模板的写法:
# /etc/rsyslog.d/business.conf $template BusinessFormat,"%TIMESTAMP% %syslogtag% %msg%\n" $template BusinessLog,"/var/log/business/%programname%.log" if $programname == 'business-app' then -?BusinessLog;BusinessFormat这里%programname%是日志来源程序名,-?BusinessLog表示异步写文件,减少 IO 阻塞。把业务日志单独落盘后,按程序名自动生成日志文件,配合 logrotate 管理,比挤在一个 messages 里强很多。
配置完成后要重启 rsyslog:
systemctl restart rsyslog然后手动打一条日志测试:
logger -t business-app "this is a test"如果没有生效,用rsyslogd -N1检查配置语法,这个命令很实用,每次改完配置我都习惯跑一遍。
3.3 远程日志转发:集中收集多台机器的日志
服务器多了以后,逐台翻日志效率太低,通常会把日志集中到一台日志服务器上。rsyslog 有两种远程传输方式:传统 UDP/TCP 和 RELP。
传统方式配置很简单,服务器端开启监听,客户端把日志转发过去。服务端配置:
# /etc/rsyslog.conf module(load="imudp") input(type="imudp" port="514") module(load="imtcp") input(type="imtcp" port="514")客户端直接把规则改成远程地址即可:
# /etc/rsyslog.d/client.conf *.info;mail.none;authpriv.none;cron.none @192.168.1.100:514如果是 RELP 协议,需要在两端加载omrelp和imrelp模块,优点是不会丢日志,适合关键业务日志传输。考虑到 UDP 会丢包、TCP 会丢连接,如果日志链路中断后果严重,优先用 RELP 或至少 TCP 传输。
注意:远程日志必须起一个独立的日志存储分区或独立磁盘,防止日志服务器自身磁盘爆掉导致业务连带故障。同时要控制访问源,避免日志接口暴露在公网上被恶意灌入数据。
4. logrotate 轮转:防止日志无限增长
日志轮转是日志管理最基础也最容易被忽略的一环。如果不轮转,一个日志文件可能涨到几个 GB,排查时编辑器打开都卡,某些应用甚至因为磁盘满直接崩溃。logrotate是日志轮转的标准工具,由 cron 定时调度,日常运维必须掌握。
4.1 负责轮转的机制与关键参数
logrotate 的主配置文件是/etc/logrotate.conf,子配置在/etc/logrotate.d/目录下。系统每天通过 cron 执行/etc/cron.daily/logrotate脚本来触发轮转,所以轮转周期最小也就是“日”。
最常用的参数要理解清楚:
daily/weekly/monthly:轮转的时间周期,生产环境大多用 daily。rotate 7:保留 7 个旧归档文件,超过则删除最旧的。compress:启用 gzip 压缩归档,能显著节省空间。delaycompress:轮转时先不压缩上一轮的文件,因为有些程序还在写旧文件句柄,延迟一天压缩可以避免漏记日志。missingok:日志文件不存在时跳过,不报错。notifempty:文件为空不做轮转。copytruncate:复制日志文件内容后清空原文件,适合不支持 reopen 的应用。create 0640 root root:轮转后新建空日志文件,并设置权限。
4.2 为业务日志编写专属轮转规则
写一个 nginx 日志的轮转规则示例:
# /etc/logrotate.d/nginx /var/log/nginx/*.log { daily rotate 14 missingok notifempty compress delaycompress sharedscripts postrotate if [ -f /var/run/nginx.pid ]; then kill -USR1 `cat /var/run/nginx.pid` fi endscript }postrotate脚本的作用是在日志轮转后让 nginx 重新打开日志文件,否则 nginx 还会往已经被改名的文件里写。kill -USR1是向 nginx 发送重开日志文件的信号,这种优雅重载方式在生产环境很常用。
写完后先用logrotate -d /etc/logrotate.d/nginx做一次调试模式运行,它会输出执行计划但不会实际轮转,确认无误后执行logrotate -f /etc/logrotate.d/nginx强制轮转一次。
4.3 自定义脚本排查轮转是否生效
新建了配置不等于轮转生效,线上经常遇到配置写好了但不轮转的情况。排查时我习惯按三步走。
先确认 cron 是否真的跑过 logrotate,查看/var/log/cron日志:
grep logrotate /var/log/cron如果看到运行记录但文件没轮转,检查该文件的父目录空间是否足够,以及文件大小是否为 0,notifempty会导致空文件不轮转。再用logrotate -d调试模式看具体执行情况,它能打印出每一条规则的匹配结果。
分享一个心得:先在测试环境把所有轮转规则都强制跑一遍,确认 postrotate 脚本不会报错,再部署到生产。轮转过早或脚本写错,可能丢失还在缓冲中的日志,这个代价远高于多花半小时测试。
5. 日志分析实战与典型故障排查
管理日志的最终目的是为了快速定位故障。这一节我把日志分析和问题排查的方法分开讲,每个都是实际工作里反复验证过的套路。
5.1 高频排查类故障速查手册
整理一个常见故障的检查路径,能帮助快速定位。
| 故障现象 | 优先查看的日志 | 常见原因 |
|---|---|---|
| SSH 无法登录 | /var/log/secure 或 auth.log | 密码错误次数过多、指纹变更、iptables 拦截 |
| 服务器突然卡顿 | dmesg、/var/log/messages | OOM kill、磁盘 IO 阻塞、高负载 |
| 应用程序启动失败 | journalctl -u 服务名 | 依赖服务未启动、配置文件语法错误、端口被占用 |
| 磁盘空间告警 | du -sh 各日志目录 | 日志未轮转、应用写日志过猛 |
| 核心服务频繁重启 | journalctl -u 服务名 -p err | 内存溢出、配置触发 reload 崩溃、外部依赖抖动 |
| 网络连接异常 | /var/log/messages、dmesg | 网卡链路问题、驱动异常、防火墙丢包 |
这张表基本覆盖了运维中最常见的六类问题。遇到问题时先对照表格定位日志源,再结合时间点过滤,效率高很多。
5.2 基于日志的有效排障五步套路
我总结了一套相对通用的排障流程,在指导新手时很管用。
第一步,锁定时间范围。故障报告的出错时间、一起出现异常的监控时间点,都是有力线索。第二步,筛选异常级别。用-p err或-p warning把干扰信息过滤掉。第三步,追踪关键进程。用journalctl -u或 grep 按进程名过滤,观察异常前后的关联事件。第四步,交叉对比多来源日志。比如应用报连接超时,同时看网络日志和防火墙日志,确认是链路问题还是应用问题。第五步,保留现场。排查完不要马上清日志,先备份出问题时间段的日志片段,留作事后分析和复盘。
这套方法的精髓是:不要盲目地从一个文件翻到另一个文件,要带着时间线假设去验证,用多个日志源互相确认。
5.3 日志被写满如何定位元凶
OOM 时日记这种场景,最怕的是不知道哪个进程写出来的。
我的排查套路是这样的。先用du -ah /var/log | sort -rh | head -20看哪个文件长得最快;再用lsof | grep deleted找占用已删除文件句柄的进程,有些应用一直在写已被轮转删除的旧文件,空间不会真正释放;再用journalctl --disk-usage看 journald 的占用;最后检查 rsyslog 是否在向某个远程端疯狂重试。
之前遇到过一个情况,某个 Java 应用把日志写到 stdout,被 systemd 捕获进 journald,而 journald 的SystemMaxUse没设置,结果把 50G 分区写满。定位到原因后,我一边清理日志,一边在应用侧把 stdout 日志输出关掉,最终定位到根因并治好了。
6. 日志分析技巧与实际案例复盘
解决了“如何收集和存储日志”,接下来要面对的才是更有价值的问题:如何从日志里挖掘出真正有用的信息。很多故障,日志里其实早就给出了答案,关键看你有没有耐心去读、有没有方法去筛。
6.1 关键词统计与格式转换
日志分析最核心的两个操作是“提取”和“统计”。grep是基础,awk是进阶,journalctl自带 JSON 输出能配合 jq 用到飞起。
统计某个时间段里错误次数最多的服务,可以用一行命令:
journalctl --since "2026-01-20 00:00" --until "2026-01-20 23:59" -p err \ | awk '{print $6}' | sort | uniq -c | sort -rn | head -20这条命令的作用是把错误日志按第六列(通常是进程名)聚合并排序,一眼就能看出哪个服务出错的次数最多。
如果需要结构化分析,journald 支持 JSON 格式输出:
journalctl -u nginx.service --output=json-pretty | jq -r '.MESSAGE' | head -50使用 JSON 输出后,可以利用 jq 做更复杂的字段筛选、内容解析和统计,非常适合写脚本做自动化告警。
6.2 一次日志致磁盘故障的完整复盘
用一个之前处理过的案例来完整走一遍排障流程。
某天监控平台报警,某台测试机根分区使用率超过 95%。我登录机器后用df -h确认了分区状态,然后执行du -ah /var/log 2>/dev/null | sort -rh | head -10,看到有个应用日志文件已经到了 20G。
进一步排查发现,这个应用出现了一个死循环,不断往日志文件里重复写相同的内容。正常情况下这个应用的日志量每天不到 100M,这明显是反常的。我先用 logrotate 强制轮转一次腾出空间,再定位到进程,配合开发一起修复了死循环。
事后我做了三件事:给所有业务日志的 logrotate 规则加了minsize 50M,防止低流量日志频繁轮转;给 journald 设置了SystemMaxUse上限;给根分区的磁盘使用率加了 80% 告警阈值。这三项措施基本杜绝了同类事件再次发生。
6.3 日志权限与安全加固
日志里往往包含敏感信息,权限控制不可忽视。默认情况下/var/log/下大部分文件是 root 所有,但业务系统里有时需要让特定组读取日志排障,这时建议使用chown root:logreaders配合组权限,而不是直接 777。
安全加固方面有几个重要点:一是日志目录和文件不能让普通用户随意删除或篡改,建议启用chattr +a让日志只允许追加;二是远程日志传输尽量走加密通道,如果日志内容包含用户敏感数据,纯文本传输风险较大;三是日志服务器要做好访问控制,防止外部机器向日志接口灌数据,干扰排查;四是保留日志管理员的操作审计,避免日志被内部人员悄悄删除。
我用chattr +a加固关键日志文件后,即使 root 用户误操作也无法直接删除或覆盖,只能先去除该属性。需要轮转清理时,先chattr -a再交给 logrotate 处理,否则轮转脚本会失败。
7. 备选方案与常见问题讨论
日志管理不是只有一种路径。根据不同场景,可以组合出不同的方案。这一节把常见问题和备选方案做一个整理,方便在实际选型时参考。
7.1 日志采集工具选型建议
除了系统自带的 journald + rsyslog,生产环境还会用到专门的日志采集工具。最常见的三类:
- 轻量文本采集:适合单机、业务规模不大的场景,直接 rsyslog + logrotate 即可,零成本、易维护。
- 集中采集与检索:适合几十台服务器的中等规模,可以用集中式日志系统,把多台机器的日志统一收集、索引和搜索。
- 云端托管方案:适合业务上云或者不想自建日志系统的团队,直接把日志通过采集 Agent 接入云日志服务,按量付费。
选型时建议先评估自身规模:机器少于十台,用 rsyslog 集中收集就够;几十台以上有检索需求,再考虑集中式日志系统;如果日志量极不稳定,或者需要长时间保留,优先考虑弹性扩容的云端方案。盲目追求“全家桶”只会增加维护成本。
7.2 日志管不过来的常用应对清单
| 问题 | 我的处理手段 | 备注 |
|---|---|---|
| 日志文件不可写 | 检查属主属组、ACL 权限、磁盘是否只读 | 应用以非 root 身份运行常见 |
| 服务不输出日志 | 检查是否输出到 stdout 且被 journald 捕获,或 rsyslog filtering 规则排除 | logger -t配合测试 |
| journald 占用过大 | 调 SystemMaxUse,执行 vacuum,确认清理策略 | 需排除它自动扩容的误区 |
| 轮转后应用仍写入旧文件 | postrotate 发送重开信号,或用 copytruncate | 常见于 nginx、tomcat |
| 远程日志收不到 | 检查端口、网络策略、rsyslog 模块是否加载 | 先用logger发测试日志 |
这张清单基本涵盖了日常运维中日志模块最常见的故障。碰到问题时不妨把它当成排查 checklist 用。
7.3 使用 systemd-tmpfiles 补充清理场合
有些环境不方便依赖 cron 调度,或者需要更精细的控制。systemd 世界其实自带一个 tmpfiles 机制,可以按规则清理目录下的过期文件,适合处理一些临时文件和应用缓存。
在/etc/tmpfiles.d/下新建配置:
# /etc/tmpfiles.d/clean-app-logs.conf R /var/log/myapp/old/7d配置里R表示递归清理该目录下超过 7 天的文件,启用了 systemd-tmpfiles-setup 的系统会自动周期执行。这个机制对处理一些非标准日志路径特别有效,很多微服务框架自己生成的临时调试文件能靠它自动收拾。
8. 总结和日志管理的收尾心得
整理日志管理这套内容时,我个人最深的体会是:日志管理说到底不是“技术堆料”,而是“预期管理”。你要提前设定好磁盘空间预期,设定好数据保留预期,设定好故障排查的响应预期,剩下的才是具体工具怎么用。
有几个经验值得单独重复一遍。第一,在每台新服务器上线时,就把journald.conf的SystemMaxUse和 logrotate 规则一次性配好,不要等出问题再补救。第二,日志的权限和安全在权限设计初期就要考虑,不要到审计事件发生后再来救火。第三,养成定期检查日志的习惯,每天花两分钟看一眼/var/log/messages或journalctl -p err --since "1 hour ago"的报错量,很多故障在用户发现之前其实已经暴露了端倪。
最后分享一个我自己用得特别顺手的技巧:在 Bash 里给 journalctl 配个短别名,提升日常操作效率:
alias jerr='journalctl -p err -b --no-pager | tail -100' alias jnow='journalctl -f'把这些别名放进~/.bashrc,日常巡检用jerr快速扫错误,值班盯日志用jnow实时跟踪,比反复输入完整的 journalctl 参数省事得多。日志管理的学习曲线不算陡,关键是动手多试、遇事多看、事后复盘,把积累的经验转成沉淀下来的规则和模板,你的运维效率会肉眼可见地提升。