rsyslog 与 journald 双写日志重复或丢失排查

    发布时间: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