发布时间:2026-09-23 12:30 更新时间:2026-09-23 12:30 阅读量:0
很多站长在服务器上会看到这样一幕:某个服务的同一条日志,在 journalctl -u xxx 里出现一次,在 /var/log/messages 里又出现一次;更麻烦的是,有时候 /var/log/messages 里干脆少了几行,翻 journal 才发现那条记录明明存在。这类“重复或丢失”往往不是应用写了两遍,而是 rsyslog 与 systemd-journald 之间的日志链路同时存在两条入口,再加上 journald 自身的速率限制,导致采集结果不稳定。下面从现象入手,把输入模块差异、限流影响和统一出口的配置思路讲清楚。
现代发行版里,服务的标准输出和标准错误默认由 systemd 接管,先写进 journald,再由 journald 决定是否转发给 rsyslog。而 rsyslog 侧读取 journal 数据时,常见有两种输入模块:imjournal 和 imuxsock。
imuxsock 监听的是传统的 /dev/log 套接字,应用调用 syslog(3) 直接往这里写;imjournal 则是通过 journald 的接口把 journal 里的条目读出来。如果一台机器上同时加载了这两个模块,那么一条经由 journald 落盘、又通过 /dev/log 转发的消息,就可能被采集两次,于是出现重复。反过来,如果 journald 把消息转发给 rsyslog 的路径被限速或配置遗漏,rsyslog 又只依赖单一来源,就会出现“journal 里有、messages 里没有”的丢失现象。
先确认当前到底加载了哪些模块,可以看 rsyslog 的配置加载情况:
# 查看 rsyslog 实际生效的模块与输入配置
sudo rsyslogd -N1
列出配置目录,确认是否在多个文件里重复加载模块
ls -l /etc/rsyslog.conf /etc/rsyslog.d/
grep -Rn "imjournal\|imuxsock\|ModLoad" /etc/rsyslog.conf /etc/rsyslog.d/
rsyslogd -N1 只做配置语法检查并打印加载信息,不会真正修改运行状态,适合先摸底。不同发行版默认文件位置略有差异,具体以实际环境为准。
journald 对单位时间内接收的消息数量有默认限制,触发限流后,超出的消息会被丢弃,或者被打上“Suppressed N messages”的标记。这个限制由 /etc/systemd/journald.conf 里的 RateLimitIntervalSec 与 RateLimitBurst 控制。突发流量大的服务(比如访问日志直接走 stdout 的 Web 服务)很容易撞上它,表现为 journal 里日志被截断,转发到 rsyslog 的自然也就少了。
排查时可以先用 journalctl 看有没有丢弃提示:
# 查看 journald 是否报告过丢弃消息
sudo journalctl -b | grep -i "suppressed\|ratelimit\|dropped"
查看 journald 当前生效的限制参数
systemctl show systemd-journald | grep -i ratelimit
如果确实被限流,可以在 /etc/systemd/journald.conf 中把限制放宽甚至关闭(按业务需要权衡,不建议长期全关,否则异常刷屏会撑爆磁盘):
# /etc/systemd/journald.conf 片段
RateLimitIntervalSec=30s
RateLimitBurst=10000
需要排查阶段临时关闭限流时可用 RateLimitIntervalSec=0
改完执行 sudo systemctl restart systemd-journald 生效。至于顺序问题,rsyslog 从 journal 读取再转发,本身是异步的,跨来源(imjournal 与 imuxsock)的时间戳精度、接收时序可能不一致,所以同一条链路里出现“后发生的先落盘”并不奇怪。真正要避免的是同一批消息走两条入口,顺序错乱多半是双入口叠加的副作用。
比较稳妥的做法是二选一,让日志只有一个来源进入 rsyslog。如果服务由 systemd 托管、日志走 stdout,推荐保留 imjournal,不再加载 imuxsock;如果还有大量应用直接调用 /dev/log,则保留 imuxsock,并让 journald 保持默认不额外转发。关键是不要两个都开。
以只保留 imjournal 为例,在 /etc/rsyslog.d/ 下集中管理,先注释掉其他文件里重复的模块加载行,再写自己的入口配置:
# /etc/rsyslog.d/10-journal.conf
module(load="imjournal"
StateFile="imjournal.state"
Ratelimit.Interval="0"
Ratelimit.Burst="0")
把 journal 读到的消息按设施和级别写入本地文件
template(name="myFormat" type="string"
string="%TIMESTAMP% %HOSTNAME% %syslogtag%%msg%\n")
authpriv.* /var/log/secure
*.info;mail.none;authpriv.none;cron.none /var/log/messages
上面 Ratelimit.Interval="0" 表示让 imjournal 自己的读取端不做额外限速,但 journald 侧的限流仍会生效,两处要一起看。修改后先做语法检查再重启:
sudo rsyslogd -N1
sudo systemctl restart rsyslog
观察一段时间,确认不再重复、不再丢失
sudo journalctl -f -u rsyslog
如果机器上还有远程 syslog 转发需求,建议也统一从 rsyslog 这一条出口走,避免 journald 直接转发和 imjournal 采集同时存在,否则远端同样可能收到重复条目。模块加载、状态文件路径等细节在不同发行版上可能不同,以官方文档和实际环境为准。
最后给一个排查顺序:先用 rsyslogd -N1 确认模块是否重复加载,再用 journalctl 确认是否被限流,然后固定单一入口并统一转发出口,最后用 journalctl -f 与 tail -f /var/log/messages 对照观察一段时间。这样处理下来,重复和丢失基本都能定位到具体环节,而不是靠反复重启碰运气。
| 📑 | 📅 |
|---|---|
| Linux conntrack 表满导致丢包:现场定位与容量评估 | 2026-09-23 |
| Nginx客户端与后端长连接谁在复用:端口耗尽排查顺序 | 2026-09-23 |
| Linux 服务器 CPU 软中断 si 偏高排查:网卡多队列、RPS 与内核参数调整 | 2026-09-23 |
| Docker 容器启动即退出排查:exit code、logs 与前台进程 | 2026-09-23 |
| MySQL单表过亿后的分页优化:延迟关联与覆盖索引 | 2026-09-23 |
| PostgreSQL表膨胀与autovacuum不生效排查实战 | 2026-09-23 |
| Redis 主从切换后写入报 READONLY:三种拓扑的误配排查 | 2026-09-23 |
| Linux负载高但CPU空闲:D状态进程与不可中断睡眠排查 | 2026-09-24 |
| Nginx 与 CDN 回源 IP 不一致:XFF 取值顺序与日志字段 | 2026-09-24 |
| Docker 容器内 Nginx 与宿主 Nginx 端口冲突排查 | 2026-09-24 |