1. 日志管理这件事为什么值得单独拎出来讲刚入行那会儿我对日志的理解就停留在“出问题了去/var/log底下翻一翻”这个层面。直到有一次线上服务半夜挂了我登录机器面对一个 8 个 G 的messages文件tail卡了半天grep跑得风扇狂转最后靠less加shiftg硬翻才在几万行里定位到一条磁盘写满的报错。那次之后我才真正意识到日志管理不是“会看日志”这么简单它是一套从产生、轮转、存储、检索到清理的完整工程习惯。你不管它它就反过来搞你。这篇内容我想聊的就是 Linux 环境下日志管理这套东西。它适合谁我觉得三类人最该看一是刚接手 Linux 服务器、还在用cat硬看日志的新手二是负责几台到几十台机器、被磁盘告警折腾过的运维或后端三是对系统可观测性有要求、想把日志这摊事理顺的开发者。核心关键词就一个——日志管理围绕它展开的是日志的采集、轮转、集中检索和容量控制。我不会只告诉你journalctl怎么用更想讲清楚为什么这么设计、参数怎么算、坑在哪里。先把结论摆前面Linux 日志管理有两条主线一条是老牌的rsyslog加logrotate组合另一条是systemd-journald这套二进制日志体系。两者不是替代关系而是并存互补很多发行版上它们同时跑着。你要做的是搞清楚每条线各自管什么、边界在哪然后针对自己的场景做取舍。下面我按“整体设计思路—核心细节—实操落地—问题排查”这个顺序往下拆中间穿插我自己踩过的坑和实测有效的做法。2. 整体设计与思路拆解两套体系为什么并存2.1 rsyslog 与 journald 的分工逻辑很多人第一次接触会困惑既然有了systemd-journald为什么还要留着rsyslog反过来也一样。要理解这个得先看两者各自的定位。journald是 systemd 生态的一部分它直接从内核、服务进程的标准输出、syslog socket 等多个来源抓日志存成带结构化字段的二进制文件查询快、字段全还能按服务单元、PID、优先级过滤。而rsyslog是一个成熟的 syslog 守护进程强项在于规则路由和远程转发——它能按 facility、severity、来源等条件把日志分发到不同文件、不同目录甚至转发到远端服务器。所以常见的架构是这样journald负责本地采集和短期存储rsyslog从 journald 或 syslog socket 读取按规则落盘到/var/log/下的文本文件同时承担向集中日志平台转发的职责。这个分工的好处是各取所长——journald 的结构化查询能力用来做快速排障rsyslog 的文本落盘和转发能力用来做长期归档和集中管理。你要是把两者对立起来非要二选一反而会丢掉其中一方的优势。我见过有团队为了“简化”直接把 rsyslog 停掉只留 journald。结果呢日志全在二进制文件里想拿awk、sed做文本处理就得先journalctl -o json转一道脚本复杂度上去了更要命的是远程转发没配好机器一挂日志跟着丢。这就是没想清楚边界。我的建议是本地排障靠 journald长期归档和转发靠 rsyslog两条线都留着各干各的活。2.2 日志轮转为什么必须做不做会怎样日志轮转log rotation是日志管理里最容易被忽视、又最容易出事的一环。原理很简单日志文件不能无限增长得按时间或大小切分旧的压缩、超期的删除。听起来是小事但不做的后果很直接——磁盘写满服务写日志失败进而可能引发进程异常甚至整机不可用。我前面说的那次半夜事故根子就是轮转策略配得太松单个文件上限设了 500M但保留份数给了 20 份算下来光一个messages就能吃掉 10G。这里有个简单的容量估算值得每个人动手算一遍。假设某服务每天产生日志约 200MB你希望保留 14 天压缩比按常见的 10:1 估算那么磁盘占用大约是200MB × 14 / 10 ≈ 280MB压缩后加上当天的未压缩文件 200MB总共不到 500MB。这个量级对大多数机器都很轻松。但如果你把保留天数设成 90 天、又不压缩那就是200MB × 90 18GB小磁盘的机器直接告急。所以轮转策略的核心不是“配个数字”而是先估算日增量再倒推保留策略让磁盘占用落在可控区间。2.3 集中式日志与本地日志的取舍单机日志管理做到位只能解决“这台机器不出事”。一旦机器数量上去登录每台去grep就不现实了。这时候要考虑集中式日志把所有机器的日志汇总到一个地方统一检索、统一告警。常见做法是用 rsyslog 的远程转发功能把日志发到一台日志服务器或者接入更完整的日志平台。但集中式不是无脑上。它带来三个新问题网络带宽、日志丢失风险、以及日志服务器本身的容量规划。我的经验是分阶段来机器少于十台先把本地轮转和 journald 查询做扎实够用超过十台或者有合规留存要求再上集中式。上集中式时转发链路一定要配磁盘缓冲队列防止网络抖动时日志直接丢——rsyslog 的action.queue相关参数就是干这个的后面实操部分我会给具体配置。这个取舍背后其实是个成本问题本地管理成本低但检索效率差集中管理检索强但要多维护一套东西按规模选就行别一上来就搞大而全。3. 核心细节解析与实操要点3.1 journald 的关键配置项怎么调journald的配置文件在/etc/systemd/journald.conf里面参数不少但真正影响日常的就这么几个。第一个是Storage可选volatile只存内存重启即失、persistent存/var/log/journal重启保留、auto有目录就持久化没有就内存。生产环境我一般显式设成persistent避免重启后关键日志丢失。第二个是SystemMaxUse控制 journal 占用的磁盘上限这个必须设否则默认可能吃掉磁盘的 10%。第三个是SystemMaxFileSize单个 journal 文件的大小上限影响轮转粒度。调这几个参数有个顺序先定SystemMaxUse再定SystemMaxFileSize最后看MaxRetentionSec按时间保留。举个例子一台 40G 磁盘的机器我给SystemMaxUse2GSystemMaxFileSize100M这样最多 20 个文件轮着来检索时不会因为单文件太大而变慢。改完配置记得systemctl restart systemd-journald然后journalctl --disk-usage确认实际占用。这里有个细节SystemMaxUse是软上限journald 在清理时可能略微超出别指望它精确到字节。注意Storagepersistent需要/var/log/journal目录存在有些精简系统默认没有这个目录得手动mkdir -p /var/log/journal再重启服务否则配置不生效。3.2 logrotate 配置文件的四段式结构logrotate的配置我习惯按四段来理解和写匹配哪些文件、怎么轮转、轮转后做什么、保留多少。一个典型的配置长这样/var/log/myapp/*.log { daily rotate 14 size 100M compress delaycompress missingok notifempty copytruncate create 0640 appuser appgroup }逐行解释一下背后的逻辑。daily和size 100M同时写时是“满足任一条件就轮转”即每天一次或文件到 100M 就切这个组合适合日志量波动大的服务。rotate 14是保留 14 份历史。compress压缩旧文件delaycompress让最近一份先不压方便还在写的进程继续追加——这个细节很多人漏掉导致压缩时和写入进程抢文件。copytruncate是给那些不支持重新打开日志文件的程序用的先复制再清空原文件代价是复制瞬间可能丢几行日志。如果程序支持SIGHUP重开文件更推荐用postrotate发信号而不是copytruncate。create 0640 appuser appgroup这行也别省它保证轮转后新文件的权限和属主正确否则可能出现新日志文件属主变成 root、应用写不进去的情况。我踩过这个坑某次轮转后应用突然报“权限拒绝”查了半天才发现是create没配新文件默认 root 属主。3.3 日志级别与 facility 的对应关系syslog 体系里有两个维度facility谁产生的和severity多严重。facility 常见的有auth认证相关、cron定时任务、daemon后台服务、kern内核、local0到local7留给自定义应用。severity 从高到低是emerg、alert、crit、err、warning、notice、info、debug。rsyslog 的规则就是靠这两个维度做路由的。理解这个对应关系写规则时就不容易乱。比如你想把认证失败单独拎出来规则可以写auth.warning /var/log/auth-warnings.log意思是 facility 为 auth、severity 为 warning 及以上的都进这个文件。注意 severity 是“及以上”写warning会同时捕获err、crit这些更严重的。自定义应用建议用local0到local7别去挤daemon否则和系统服务混在一起排查时很难区分。这个约定俗成的分配方式团队内部最好统一写进文档不然换个人接手就乱套。3.4 日志文件权限与敏感信息处理日志里经常混着敏感信息——认证 token、用户标识、请求参数。默认的/var/log权限是755日志文件多为640属主root、属组adm或syslog。这个权限意味着同组用户能读其他用户不能。如果你的应用日志里有敏感字段光靠文件权限不够得在应用层做脱敏或者在 rsyslog 落盘前用模板过滤。我一般会做两件事一是给应用日志单独建目录权限设750属组只放需要看日志的人二是定期审计日志内容用grep扫一遍常见敏感模式比如长串的十六进制、password这类关键字发现就回头改应用代码。这事听起来麻烦但真出过一次日志泄露之后你会觉得这点功夫花得值。权限这块没有一劳永逸的方案只能靠约定加定期检查。4. 实操过程与核心环节实现4.1 从零配置一套 journald 持久化存储假设你接手一台新机器要先把 journald 的持久化配好。第一步确认目录ls -ld /var/log/journal不存在就mkdir -p /var/log/journal。第二步编辑/etc/systemd/journald.conf把下面几项取消注释并改成目标值[Journal] Storagepersistent SystemMaxUse2G SystemMaxFileSize100M MaxRetentionSec30day第三步重启服务并验证systemctl restart systemd-journald然后journalctl --disk-usage看当前占用journalctl --verify检查文件完整性。第四步做一次实际查询验证字段过滤是否好用比如journalctl -u sshd --since 1 hour ago -p warning这条命令按服务单元、时间、优先级三个条件过滤是日常排障最常用的组合。这里有个参数选择的计算过程值得说清楚。SystemMaxUse2G是怎么来的我按“保留 30 天、日均日志 50MB、压缩后约 5MB/天”估算30 天约 150MB留足余量给突发流量2G 足够覆盖。如果你的机器日志量大比如日均 500MB那 2G 只够存三四天就得往上调或者缩短MaxRetentionSec。先估日增量再定上限这个顺序不能反。4.2 手写一份生产可用的 logrotate 配置接着给一个自定义应用配轮转。假设应用日志在/var/log/myapp/下程序支持SIGHUP重开文件。配置写到/etc/logrotate.d/myapp/var/log/myapp/*.log { daily rotate 14 maxsize 200M compress delaycompress missingok notifempty sharedscripts postrotate /bin/kill -HUP cat /var/run/myapp.pid 2/dev/null 2/dev/null || true endscript create 0640 appuser appgroup }几个点展开说。maxsize 200M和daily配合实现“每天切或超 200M 就切”。sharedscripts保证多个匹配文件只执行一次postrotate避免重复发信号。postrotate里的|| true是兜底防止 pid 文件不存在时整个轮转脚本报错退出。写完别急着等定时任务先手动测logrotate -d /etc/logrotate.d/myapp是 dry-run只打印不执行用来检查配置语法和匹配逻辑确认无误后logrotate -f /etc/logrotate.d/myapp强制跑一次看文件是否按预期切分、压缩、权限是否正确。注意logrotate默认由 systemd timer 或 cron 每天触发手动-f测试完记得检查/var/lib/logrotate/status里的记录避免测试打乱了正常轮转节奏。4.3 rsyslog 规则路由与远程转发配置本地落盘配好后如果要集中转发就在/etc/rsyslog.d/下加一个配置文件比如50-forward.conf*.* logserver.example.internal:514表示 TCP表示 UDP。生产环境一律用 TCPUDP 丢包你根本不知道。但光这一行不够网络抖动时会丢日志得加磁盘缓冲队列*.* action( typeomfwd targetlogserver.example.internal port514 protocoltcp queue.typedisk queue.filenamefwdq queue.maxdiskspace1g queue.saveonshutdownon action.resumeRetryCount-1 )queue.typedisk让日志先落本地队列再发queue.maxdiskspace1g限制队列占用action.resumeRetryCount-1表示无限重试直到成功。这套配置的意义在于日志服务器短暂不可达时日志在本地排队不丢恢复后自动补发。改完systemctl restart rsyslog然后用logger -p local0.info test message发一条测试日志去日志服务器上确认收到。这个测试步骤别省我见过配了转发但防火墙没放行、日志静默丢失好几天才发现的情况。4.4 日志检索的常用组合与性能考量日常排障journalctl和grep是主力。journalctl的优势是结构化过滤几个高频组合我列一下按时间--since 2024-01-01 08:00 --until 2024-01-01 09:00按服务-u nginx按优先级-p err实时跟踪-f输出 JSON 便于程序处理-o json-pretty。文本日志则靠grep加awk比如统计某接口的 5xx 数量grep 500 access.log | wc -l。性能上有个经验先缩小范围再匹配。直接对一个几 G 的文件grep很慢先用journalctl --since或按日期切分的文件名缩小到小时级再grep速度差一个数量级。另外journalctl的--no-pager在脚本里必加否则它会调用分页器卡住。这些细节不起眼但天天用顺手了效率差别很大。5. 常见问题与排查技巧实录5.1 磁盘被日志写满的应急处理这是最高频的事故。现象是服务报“No space left on device”df -h一看某分区 100%。应急处理分三步先定位大文件du -sh /var/log/* | sort -rh | head再确认能不能删——正在被进程打开的文件直接rm不会释放空间得用 filename清空或者重启对应服务。清空后df -h确认空间释放然后回头改轮转策略把根因解决掉。排查根因时重点看两处/etc/logrotate.d/下有没有漏配的服务以及 journald 的SystemMaxUse有没有设。我遇到过一次是某个自定义应用日志没纳入轮转一个月涨到 30G。教训是新服务上线日志轮转配置要和部署脚本一起提交别指望事后补。5.2 日志轮转后应用写不进去的排查轮转后应用报权限错误八成是create那行没配或者配错。排查顺序ls -l看新文件属主和权限对比应用运行用户看logrotate配置里create的属主属组是否匹配如果用了copytruncate检查是不是复制过程中文件被锁。解决办法就是补上正确的create行然后手动触发一次轮转验证。还有一种情况是应用持有旧文件句柄轮转后继续往已改名的文件写新文件一直是空的。这种要么用postrotate发信号让应用重开文件要么用copytruncate。判断方法轮转后lsof | grep deleted看有没有进程占着已删除文件有的话就是句柄没释放。5.3 journald 日志丢失或查询不到的定位journalctl查不到预期日志先确认Storage是不是volatile——内存存储重启就没了。再看journalctl --disk-usage是否触顶被清理SystemMaxUse设太小会导致旧日志被提前删。还有一种隐蔽情况服务的日志输出没被 journald 捕获比如程序自己写文件而没走 stdout/stderr那 journald 自然看不到得去查应用自己的日志文件。排查时可以用journalctl -u 服务名 --no-pager | tail看最近有没有输出没有的话检查服务的StandardOutput配置。systemd 单元里StandardOutputjournal才会进 journald设成null或文件路径就不进。这个配置项容易被忽略尤其是从别处拷来的单元文件。5.4 常见问题速查表现象可能原因排查命令处理方向磁盘满日志未轮转或保留过多du -sh /var/log/* | sort -rh清空大文件补轮转配置轮转后应用报权限错create未配或属主错ls -l 日志文件补create行并验证新日志文件为空应用持有旧句柄lsof | grep deleted加postrotate发信号journalctl 查不到日志Storage 为 volatile 或触顶清理journalctl --disk-usage改 persistent调大上限远程转发丢日志无磁盘队列或网络中断查 rsyslog 队列状态配queue.typedisk日志检索慢单文件过大或范围太宽ls -lh看文件大小缩小时间范围调小单文件上限这张表我建议贴在运维手册里出事时按图索骥比临时想快得多。但表是死的真正管用的是平时把配置做扎实、把测试做完整。日志管理这事的本质是在问题发生前把可观测性铺好而不是等出事了再去翻日志。我现在的习惯是每接一台新机器先把 journald 持久化、logrotate 模板、转发队列三件事配完再谈别的。这套流程跑顺了半夜被叫起来查日志的次数会明显下降。最后分享一个小技巧给关键服务的日志加一个每日摘要任务用journalctl --since yesterday -p err统计错误条数超过阈值就发提醒。这个脚本不到十行但能让你在用户报障之前就发现问题。日志管理的价值不在于存了多少而在于你需要的时候它在那儿、找得到、看得懂。
阅读完成 · 觉得有帮助?