在Ubuntu服务器运维中,systemd-journal日志默认以二进制格式存储在/var/log/journal/目录下,如果不做任何配置,日志会无限增长直到把磁盘撑满。解决这个问题有两条核心路径:一是通过journald.conf开启日志压缩功能,二是将日志通过网络实时转发到远程服务器做集中存储。这两件事不是二选一,而是必须同时做,否则单机压缩治标不治本,远程存储又会因为数据量太大拖垮带宽。下面我把具体配置方法、参数含义、踩坑经验全部讲透。

一、先搞懂systemd-journal日志的存储机制

systemd-journald是Ubuntu 16.04之后默认的日志守护进程,它不像传统的rsyslog那样写纯文本文件,而是把日志以结构化的二进制格式存在/var/log/journal/目录中。每个日志文件的大小默认是128MB,系统会自动轮转。但问题在于,如果你的服务器跑着高并发的Web服务、数据库或者容器,每天产生几个GB的日志很正常,日积月累磁盘就会告警。

journald的配置文件在/etc/systemd/journald.conf,不过Ubuntu默认这个文件几乎是空的,所有参数都走默认值。你需要手动编辑它来控制日志的最大占用空间和压缩策略。理解这一点是后续所有操作的基础。

二、配置日志压缩:让本地磁盘只保留有限的日志

打开配置文件进行编辑:

sudo vim /etc/systemd/journald.conf

在[Journal]段落下添加或修改以下几个关键参数:

[Journal]
SystemMaxUse=2G
SystemMaxFileSize=256M
SystemMaxFiles=10
Compress=yes
Storage=persistent

逐个解释这些参数的含义。SystemMaxUse=2G表示journal日志在本地磁盘上最多占用2GB空间,超过之后最旧的日志会被自动删除。SystemMaxFileSize=256M是单个日志文件的最大体积,默认128M,调大到256M可以减少文件数量,提升读取效率。SystemMaxFiles=10限制最多保留10个轮转文件,配合SystemMaxUse一起控制总量。Compress=yes开启zlib压缩,压缩后的日志体积通常能缩减60%到80%,这是最关键的一个参数。Storage=persistent确保日志持久化保存,而不是只存在内存里重启就丢。

修改完成后必须重启journald服务才能生效:

sudo systemctl restart systemd-journald

重启之后可以用journalctl --disk-usage查看当前日志占用情况,确认配置是否生效。如果你发现磁盘上日志还是很大,检查一下是不是有其他服务在往journal里疯狂写日志,比如某个容器的stdout输出没有做限制,这种情况需要单独对那个服务做日志限流。

三、远程存储方案:把日志实时推送到集中服务器

本地压缩只能延缓磁盘压力,真正的企业级做法是把日志实时同步到一台专门的日志服务器上。systemd-journal原生支持两种远程传输方式:一种是通过journal-remote和journal-upload组合,另一种是通过journal-gatewayd提供HTTP接口。实际运维中用得最多的是第一种,稳定可靠,配置简单。

首先在日志接收服务器上安装并启动journal-remote服务。假设接收服务器的IP是192.168.1.100:

sudo apt install systemd-journal-remote
sudo mkdir -p /var/log/journal/remote
sudo systemctl enable --now systemd-journal-remote

这个服务会监听19532端口,接收来自客户端的日志流。/var/log/journal/remote目录就是远程日志的存储位置,你可以在这个目录上挂载大容量磁盘或者做LVM扩展。

然后在每台需要发送日志的Ubuntu客户端上,修改journald.conf添加远程转发配置:

[Journal]
ForwardToSyslog=no
ForwardToConsole=no
ForwardToWall=no
Compress=yes
Storage=persistent

这里把ForwardToSyslog设为no,避免日志同时往rsyslog和远程journal两个方向发造成重复。然后创建journal-upload的配置文件:

sudo vim /etc/systemd/journal-upload.conf
[Upload]
URL=https://192.168.1.100:19532

注意这里用的是https协议,journal-upload会自动建立TLS加密连接。如果你的内网环境不想配证书,可以把URL改成http://,但安全性会降低。配置好之后启动upload服务:

sudo systemctl enable --now systemd-journal-upload

到这一步,客户端的日志就会实时加密推送到远程服务器了。你可以在接收服务器上用journalctl --file=/var/log/journal/remote/remote-*.journal来查看收到的远程日志,按主机名和时间排序都没问题。

四、进阶优化:带宽控制和日志保留策略

远程传输日志最怕的就是带宽被打满。如果你有几十台服务器同时往一台日志服务器推日志,高峰期网络可能会拥塞。解决办法有两个:一是在journal-upload端配置限速,二是在接收端做日志归档和清理。

journal-upload本身没有内置限速参数,但你可以通过systemd的IOScheduling来限制它的网络优先级。在upload服务的systemd unit文件中添加:

[Service]
IOSchedulingClass=idle
IOSchedulingPriority=7

这样upload进程的网络IO优先级会被降到最低,不会抢占正常业务流量。更精细的控制可以用tc命令在网络层做流量整形,但那属于网络运维范畴,这里不展开。

接收端的日志保留策略同样重要。你不可能无限存储所有服务器的所有日志,需要定期清理。可以写一个简单的cron任务:

0 3 * * * find /var/log/journal/remote/ -name "*.journal" -mtime +30 -delete

这条命令每天凌晨3点删除30天前的远程日志文件。如果你需要长期归档,可以在删除之前先用journalctl导出为文本格式再压缩存储到冷存储上。

五、常见踩坑点和排查思路

实际部署中经常遇到几个问题。第一个是客户端日志发不出去,最常见原因是防火墙没开19532端口,用sudo ufw allow 19532/tcp解决。第二个是接收端磁盘满了日志还在往里灌,因为journal-remote默认不会拒绝写入,你必须在接收端也配好SystemMaxUse或者用外部监控脚本做告警。第三个是日志压缩没生效,检查Compress=yes是否真的写在了[Journal]段落下,而不是写到了别的地方或者被后面的配置覆盖了。

还有一个容易忽略的点:如果你的服务器用了logrotate或者自定义的日志轮转脚本去处理/var/log下的传统文本日志,不要同时让journald也去管理同一份日志输出,否则会产生冲突和重复。journald只管它自己的二进制日志,传统的应用日志走rsyslog或者filebeat是另一条路,两条路互不干扰才是最佳实践。

最后说一个实战经验:在生产环境中,建议把日志接收服务器做成高可用架构,至少两台接收节点做负载均衡,或者用NFS共享存储。单点接收服务器一旦宕机,所有客户端的upload服务会进入重试循环,虽然不会丢日志,但会占用客户端资源。做好运维监控,把journald的状态纳入你的服务器监控体系,才是长久之计。

六、总结

Ubuntu的systemd-journal日志管理本质上就是两件事:本地做压缩限容,远程做集中存储。Compress=yes和SystemMaxUse是本地控制的核心参数,journal-upload加journal-remote是远程传输的标准组合。把这两套配置做好,再加上带宽控制和定期清理策略,你的日志系统就能既省磁盘又安全可查。不要等到磁盘告警了才想起来处理,提前规划才是运维的基本功。