Linux 日志系统架构:从 syslog 到 rsyslog 与 systemd-journald
日志系统,说白了就是操作系统的“黑匣子”。
我刚入行那会儿,被线上问题搞得焦头烂额,靠 tail -f /var/log/messages 一把梭。后来才意识到,日志不只是排障工具,更是审计、合规、安全溯源的核心资产。今天我就带你看看 Linux 日志系统的底层骨架——syslog 协议、rsyslog 的进化,以及 systemd-journald 带来的新玩法。
3.1 syslog 协议:日志界的“普通话”
syslog 不是一个软件,是一种协议(RFC 5424)。它定义了日志的格式、等级和设备分类。你可以把协议理解成“所有日志说同一种语言”。
每条 syslog 消息包含三个核心字段:设施(Facility)、严重级别(Severity)、消息体。
| 字段 | 说明 | 常见值举例 |
|---|---|---|
| Facility | 标识消息来源 | kern(0)、user(1)、mail(2)、daemon(3)、auth(4)、local0~local7(16~23) |
| Severity | 紧急程度(0~7) | emerg(0)、alert(1)、crit(2)、err(3)、warning(4)、notice(5)、info(6)、debug(7) |
| 消息体 | 实际文本内容 | “Connection refused by port 22” |
你想想看,有了这个标准,任何程序只要调用 syslog() 函数,日志就能被统一收集、过滤、路由。我在项目中见过三台不同厂商的设备,一台 Linux 服务器、一台 Cisco 交换机、一台 Fortinet 防火墙,全都能把日志发到同一台 rsyslog 服务器——就是靠的这个协议。
local0 ~ local7 作为自定义设施,避免跟系统设施冲突。分配规则在团队内部用文档约定好就行。
3.2 rsyslog:高可靠的日志瑞士军刀
rsyslog 是 syslog 协议的经典实现,也是大多数 RHEL/CentOS 7/8 的默认日志守护进程。它的设计原则:稳定、可扩展、模块化。
配置文件在 /etc/rsyslog.conf 和 /etc/rsyslog.d/ 目录下。语法其实很简单:
# 格式:facility.severity action
kern.* /var/log/kern.log
*.info;mail.none;authpriv.none /var/log/messages
local0.info @192.168.1.100:514 # 远程发送
这个语法我当初第一次看觉得挺“怪”,但用习惯了就会发现它特别灵活。你可以在 severity 字段里写 =info 精确匹配,或者 !err 排除某个级别。
我曾经在线上搞过一个配置,想把所有 SSH 登录失败的日志单独存一份:
# /etc/rsyslog.d/ssh-failures.conf
authpriv.crit /var/log/ssh-auth-failures.log
配合 fail2ban 消费这个文件,效果很好。注意 authpriv 设施的 crit 级别通常对应登录失败——但不同发行版略有差异,用之前建议先 grep 一下已有日志确认关键词。
imtcp 模块。我曾经因为 UDP 丢日志,排查了整整两天才发现是网络拥塞导致尾部日志丢失——从那以后,远程日志一律用 TCP。
3.3 systemd-journald:新时代的结构化日志
systemd 成为 Linux 的 init 系统后,顺带带来了 systemd-journald。它的核心理念:结构化、二进制、自带元数据。
为什么说它“结构化”?你感受一下传统 syslog 的一条日志:
Dec 5 10:20:30 myserver sshd[12345]: Failed password for root from 10.0.0.1 port 22 ssh2
这条日志需要靠正则表达式去提取时间、主机、进程、用户名、IP。而 journald 把每条日志变成了一组键值对:
_PID=12345
_SYSTEMD_UNIT=sshd.service
MESSAGE=Failed password for root from 10.0.0.1 port 22 ssh2
_PRIORITY=4
_BOOT_ID=abc123def456
再加上 journalctl 命令,查询效率远超 grep。比如查今天凌晨 3 点的 SSH 日志:
journalctl -u sshd.service --since "2025-12-06 03:00:00" --until "2025-12-06 03:10:00"
我个人习惯在排查故障时先用 journalctl -xe 看最近几屏,如果发现对应 _TRANSPORT=journal 的日志数量异常,再用过滤条件精准定位。
3.4 双轨协作:如何让 rsyslog 和 journald 和谐共存
很多新系统(CentOS 8、Ubuntu 20.04+)默认同时运行 rsyslog 和 journald。journald 收原始结构化日志,rsyslog 从 journald 读取后再做传统文件落地。配置方式:
# /etc/rsyslog.conf 或模块配置
module(load="imjournal" JournalStateFile="/var/lib/rsyslog/imjournal.state")
*.* /var/log/syslog
这里要注意状态文件 imjournal.state 记录了 rsyslog 已经读到 journald 的哪个位置。如果状态文件损坏或丢失,重启 rsyslog 时会重复消费所有日志——我有一次在测试环境就遇到了这个坑,结果 /var/log/syslog 瞬间暴涨到几十 GB。解决办法是删掉状态文件并重启 rsyslog,但正式环境一定记得备份。
| 组件 | 优势 | 劣势 |
|---|---|---|
| rsyslog | 文本直接可读,支持远程转发,配置灵活 | 无法保留结构化字段,解析需正则 |
| systemd-journald | 结构化查询,自带索引,按 boot 分级 | 二进制文件体积大,默认无持久化(需创建 /var/log/journal) |
我的推荐策略:journald 做近端实时查询,rsyslog 做持久化归档和远程转发。这样既享受了 journalctl 的便利,又保留了传统文本日志的兼容性。
- journald 持久化:
mkdir -p /var/log/journal && systemctl restart systemd-journald - rsyslog 读取 journald:确保
imjournal模块加载且状态文件存在 - 日志轮转:
/etc/logrotate.d/rsyslog和journalctl --vacuum-size=1G双管齐下
3.5 一张表总结三者的核心区别
| 特性 | syslog 协议 | rsyslog | systemd-journald |
|---|---|---|---|
| 本质 | 协议标准 | 守护进程 + 实现 | 守护进程 + 存储引擎 |
| 日志格式 | 纯文本 | 纯文本 | 二进制(键值对) |
| 过滤能力 | 极弱 | 基于 facility/severity | 任意字段 |
| 性能 | 高 | 中高 | 中(写放大因子高) |
| 常见场景 | 网络设备、嵌入式 | 传统 Linux 服务器 | 现代 systemd 系统 |
明白这些之后,你再看任何 Linux 发行版的日志配置,其实都是在“协议(syslog)- 实现(rsyslog)- 现代替代(journald)”这个三角里做组合。碰到不熟悉的系统,先看进程:ps aux | grep -E 'rsyslog|journald',再查配置文件,90% 的日志问题都能快速定位。
嗯,这一章的内容就这么多。下一环节是实操,我们直接上手配置一台两全其美的日志服务器。