前言
就在半月之前,负责打包更新的服务器突然登录不上去了,赶紧找来运维的同事帮忙解决,发现系统日志中有很多 systemd-journald[424]: Failed to open runtime journal: No space left on device
字样的错误,被告知磁盘满了需要清理,但是我当时登录不上去,只能让他们帮忙重启后利用单用户模式上去删除临时文件试试,但重启后发现问题解决了,很是诧异,查询服务器后台监控平台,发现磁盘空间还有50%,inode只占用了0.02%,这怎么会磁盘满了呢?
问题分析
后来经过分析,应该是journal默认将系统日志存储在/run/log/journal目录中,而 /run
是一个临时文件系统,通常挂载在内存中,用于存储运行时产生的临时文件,如进程 ID 文件、锁文件等,如果登录所需的文件或进程受到 /run
空间不足的影响,可能会导致登录问题。例如,如果 sshd
进程的运行所需的文件被存储在 /run
中并且空间不足,那么可能无法正常登录。
1 | $ df -h |
所以系统重启后,这个空间释放了也就能通过ssh登录了,并且重启后journal日志清空也证实了这一点。
关于这个空间限制多数说的是10%,但是如果真是的所处分区的10%,那么不会导致我登录不上的,所以我倾向于是系统内存10%或者硬盘最大10%,默认最大限制4G,具体限制等我有空时查查文档吧,先贴一段看起来很靠谱的描述
SystemMaxUse=, SystemKeepFree=, SystemMaxFileSize=, SystemMaxFiles=, RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize=, RuntimeMaxFiles=
限制日志文件的 大小上限。 以 “System” 开头的选项用于限制磁盘使用量, 也就是 /var/log/journal 的使用量。 以 “Runtime” 开头的选项用于限制内存使用量, 也就是 /run/log/journal 的使用量。 以 “System” 开头的选项仅在 /var/log/journal 目录确实存在且可写时才有意义。 但以 “Runtime” 开头的选项永远有意义。 也就是说, 在系统启动早期 /var 尚未挂载时、 或者系统管理员禁止在磁盘上存储日志的时候, 仅有 “Runtime” 开头的选项有意义。 journalctl 与 systemd-journald 工具会忽略日志目录中 所有后缀名不等于 “.journal” 或 “.journal~” 的文件。 换句话说,日志目录中不应该存在后缀名不等于 “.journal” 或 “.journal~” 的文件, 因为这些文件 永远不会被清理。SystemMaxUse= 与 RuntimeMaxUse= 限制全部日志文件加在一起最多可以占用多少空间。 SystemKeepFree= 与 RuntimeKeepFree= 表示除日志文件之外,至少保留多少空间给其他用途。 systemd-journald 会同时考虑这两个因素, 并且尽量限制日志文件的总大小,以同时满足这两个限制。
SystemMaxUse= 与 RuntimeMaxUse= 的默认值是10%空间与4G空间两者中的较小者; SystemKeepFree= 与 RuntimeKeepFree= 的默认值是15%空间与4G空间两者中的较大者; 如果在 systemd-journald 启动时,文件系统即将被填满并且已经超越了 SystemKeepFree= 或 RuntimeKeepFree= 的限制,那么日志记录将被暂停。 也就是说,如果在创建日志文件时,文件系统有充足的空闲空间, 但是后来文件系统被其他非日志文件过多占用, 那么 systemd-journald 只会立即暂停日志记录, 但不会删除已经存在的日志文件。 注意,只会删除已归档的日志文件以释放空间。 也就是说,即使在完成日志清理之后, 日志所占用的空间仍然可能大于 SystemMaxUse= 或 RuntimeMaxUse= 的限制。
SystemMaxFileSize= 与 RuntimeMaxFileSize= 限制单个日志文件的最大体积, 到达此限制后日志文件将会自动滚动。 默认值是对应的 SystemMaxUse= 与 RuntimeMaxUse= 值的1/8 , 这也意味着日志滚动 默认保留7个历史文件。
日志大小 可以使用以1024为基数的 K, M, G, T, P, E 后缀, 分别对应于 1024, 1024², … 字节。
SystemMaxFiles= 与 RuntimeMaxFiles= 限制最多允许同时存在多少个日志文件, 超出此限制后, 最老的日志文件将被删除, 而当前的活动日志文件 则不受影响。 默认值为100个。
以上描述来自 《journald.conf 中文手册》,另外 《Systemd日志管理服务:Journald以及重要配置选项》 这篇博文也提到了默认日志数据将仅存储在内存中,在系统关闭时会删除该数据。
journal 和 syslog 对比
提到系统日志除了journal比较常见以外,还有 syslog 也是比较基础的服务,两者都是日志服务,并且在系统中合理分工,相互配合,它们服务于不同的目标并且具有不同的特性。syslog是Linux系统的一套日志框架,它既可以记录日志到本地文件,也可以通过网络发送到接收syslog的服务器,以实现对多个设备的syslog消息进行统一的存储或解析。而journal是改进型的日志管理服务,主要收集来自内核、系统早期的启动阶段的日志以及系统守护进程在启动和运行中的标准输出和错误。
在CentOS 7及更高版本中,journalctl成为了查看和管理系统日志的主要工具,它从/var/log/journal/和/run/log/journal/等路径获取日志信息。同时,systemd-journald会将日志信息写入到socket文件/run/systemd/journal/syslog中,然后由rsyslog服务监听这个socket文件,从而实现对日志的统一管理和处理。因此,可以说syslog和journalctl在日志管理中各司其职,共同保障了Linux系统日志的完整性和可用性。
以上提到了一些名词,先说明一下来清楚其中的关系,journal日志使用journalctl工具管理,依赖systemd-journald
服务,syslog日志可以用文本工具来查看,view、more、cat等命令都可以用,也可以借助其他工具查看特定信息,比如用dmesg命令查看syslog中内核相关日志,syslog依赖的服务名通常是 rsyslogd
journalctl
和 syslog
都是 Linux 系统中用于处理和查看系统日志的工具,我们从以下几个方面来对比下两者的区别:
存储方式:
syslog
使用文本文件来存储日志信息,可以通过文本编辑器查看,通常存储在/var/log/syslog
或/var/log/message
journalctl
使用systemd-journald
服务来存储二进制格式的日志文件。通常存储在/run/log/journal/
或/var/log/journal/
日志内容:
syslog
使用文本格式,记录在文本文件中。日志信息包含时间戳、主机名、应用程序名等journalctl
使用二进制格式,可以存储更多的元数据,例如进程 ID、用户 ID、SELinux 上下文等。这使得日志更加结构化,支持更高级的查询和过滤
查询和过滤:
syslog
的查询和过滤通常使用命令行工具(例如grep
)或者专用的工具(例如logrotate
)journalctl
提供了更丰富和强大的查询和过滤功能,可以按时间、服务单元、日志级别等多个条件进行过滤。这使得查找和分析特定事件更加方便
实时查看:
syslog
通常使用tail
命令实时查看日志文件的末尾journalctl
可以使用-f
或--follow
选项来实时查看最新的日志
服务和依赖关系:
syslog
是一个通用的日志服务,可以由多个日志守护进程(如rsyslog
、syslog-ng
)实现journalctl
是systemd
系统中的一部分,依赖于systemd-journald
服务
配置文件的路径:
syslog
的配置文件在/etc/rsyslog.conf
journalctl
的配置文件在/etc/systemd/journald.conf
总体而言,journalctl
是 systemd
系统的一部分,提供了更现代化、结构化和强大的日志管理功能,但这并不意味着 syslog
是过时的。在一些系统中,两者可能同时存在,而且一些工具和服务可能仍然使用传统的 syslog
。选择使用哪一个取决于系统的需求和管理员的偏好。
下面分别展示一下systemd-journald
和 rsyslogd
两个服务查询信息:
1 | [root@demo ~]# systemctl status systemd-journald |
1 | [root@demo ~]# systemctl status rsyslogd |
journal 和 syslog 配置
两个服务的配置文件都有很多内容,在此只展示其中部分重要的参数,先看一下 /etc/systemd/journald.conf
1 | [Journal] |
再看一下 /etc/rsyslog.conf
配置文件
1 | # Include all config files in /etc/rsyslog.d/ |
使用journalctl查看和管理日志
查看日志
1 | # 查看所有日志(默认情况下只保存本次启动的日志) |
查看指定服务日志
1 |
|
查看调整存储
1 | # 显示日志占据的硬盘空间 |
回到文章开头的问题
通过梳理知识,我发现通过 systemctl
命令查询 systemd-journald
服务状态可以看到日志存储路径和存储限制,分别展示一下,先看存储到内存的:
1 | root@demo1:~# systemctl status systemd-journald |
默认存储到 /run/log/journal/中,分区一共1.6G,最大max 159.9M,当前用了 8.0M,按这个来推算果然限制是10%,再看看持久化的情况
1 | root@jenkins2004:~# systemctl status systemd-journald |
看起来存到了 var/log/journal
,最大可用空间居然到了4G,这样来分析这次的问题可能不是journal日志搞的鬼,而是很多进程吧/run目录写满了,导致journal写不进去报了开头的错误,进而引发的无法登录。
总结
- syslog和journal在日志管理中各司其职,共同保障了Linux系统日志的完整性和可用性
- journal默认将系统日志存储在/run/log/journal目录中,而
/run
通常挂载在内存中,当此目录被写满时可能导致ssh无法登录 - 将
/etc/systemd/journald.conf
配置中的 Storage 字段设置为persistent
可以开启日志持久化 sudo journalctl -n 20
可以显示显示尾部最新的20行日志,-n后不加参数默认10行sudo journalctl -u nginx.service
查看ssh服务器的日志sudo journalctl --since="2023-12-22 16:52:18"
查看指定时间以后的日志
寒意一波接着一波,总会有看见“光”的时候(30厘米的下跌,摔得可真疼)