前言

运维怕什么?怕的是突然手机疯狂响起——线上服务挂了!当时那个慌啊,SSH连上服务器就开始各种tail -f、grep满天飞,结果折腾了半个多小时才找到问题根源。

后来我才意识到,其实systemd的journalctl早就为我们准备好了一套完整的日志管理方案,只是很多人(包括当时的我)都没有好好利用起来。今天就来聊聊这个被严重低估的排查利器。

什么是journalctl?为什么要用它?

journalctl其实就是systemd日志系统的查询工具。你可能会说,我用grep、awk这些传统工具不是挺好的吗?但是你有没有遇到过这样的情况:

  • 日志文件太大,grep半天没反应
  • 想看某个时间段的日志,结果要写一堆复杂的正则表达式
  • 系统重启后,之前的日志找不到了
  • 想看某个服务的完整日志链路,结果要翻好几个不同的文件

我之前就遇到过一次特别尴尬的事情。有个微服务莫名其妙CPU飙高,我用传统方法查了一个多小时,各种/var/log下的文件翻了个遍,最后发现关键信息其实在systemd的journal里,用journalctl几分钟就能定位到问题。

基础用法:从入门到不放弃

最简单的开始

journalctl

直接敲这个命令,你会看到系统从启动开始的所有日志。不过这样看起来会很乱,而且信息量巨大。

我一般习惯加个-f参数:

journalctl -f

这就像tail -f一样,实时显示最新的日志。当你怀疑某个服务有问题的时候,开着这个命令,然后去操作一下,立马就能看到相关的日志输出。

按时间查看日志

这个功能真的太实用了!比如我想看今天的日志:

journalctl --since today

或者看昨天的:

journalctl --since yesterday

更精确一点,看某个时间段的:

journalctl --since "2024-01-15 14:00:00" --until "2024-01-15 15:00:00"

有一次我们的支付服务在下午2点左右出现异常,用这个命令一下就把问题时间段的日志筛选出来了,比用grep配合时间戳要方便太多。

按服务查看日志

这个是我用得最多的功能:

journalctl -u nginx

只看nginx服务的日志。如果你想实时监控某个服务:

journalctl -u nginx -f

有时候一个服务重启了好几次,你想看它的历史记录:

journalctl -u nginx --since "1 hour ago"

进阶技巧:让你的排查效率翻倍

按优先级过滤

journalctl支持按日志级别过滤,这个功能在排查问题时特别有用:

journalctl -p err

只显示错误级别的日志。日志级别从高到低是:emerg、alert、crit、err、warning、notice、info、debug。

我记得有次数据库连接池出问题,整个系统日志刷得飞快,用journalctl -p err一下就把关键错误信息筛选出来了。

查看内核日志

journalctl -k

这个等同于dmesg,但是journalctl的输出格式更友好,而且可以结合其他参数使用。

按进程ID查看

有时候你知道某个进程有问题,可以直接按PID查看:

journalctl _PID=1234

查看启动信息

想看系统启动过程中发生了什么:

journalctl -b

如果系统重启过多次,你想看上一次启动的日志:

journalctl -b -1

这个功能在排查系统启动异常时特别有用。

实战案例:真实故障排查过程

我来分享一个真实的故障排查案例。那是个周五的晚上(为什么故障总是喜欢周五?),客户的Web应用突然故障,客户找到我们帮忙排查。

首先我用journalctl看了一下整体情况:

journalctl --since "30 minutes ago" -p warning

发现有大量的数据库连接超时警告。然后我专门看了一下数据库服务的日志:

journalctl -u postgresql --since "30 minutes ago"

发现数据库本身没什么异常。接着我查看了应用服务的日志:

journalctl -u myapp --since "30 minutes ago" | grep -i error

这里我发现了一个有趣的现象,应用在某个时间点开始出现大量的连接池耗尽错误。

然后我用时间过滤功能精确定位:

journalctl -u myapp --since "2024-01-12 19:45:00" --until "2024-01-12 19:50:00"

最终发现是某个定时任务在19:45分启动后,没有正确释放数据库连接,导致连接池被耗尽。

整个排查过程用了不到20分钟,如果用传统方法可能要花费更长时间。

高级功能:成为journalctl高手

JSON格式输出

有时候你需要程序化处理日志,可以用JSON格式:

journalctl -u nginx -o json

这样输出的每一行都是一个JSON对象,方便后续处理。

查看磁盘使用情况

journal日志会占用磁盘空间,你可以查看当前使用情况:

journalctl --disk-usage

如果空间不够,可以清理旧日志:

journalctl --vacuum-time=7d

只保留最近7天的日志。

导出日志

有时候需要把日志发给其他人分析:

journalctl -u myapp --since today > app_logs.txt

反向查看日志

从最新的日志开始看:

journalctl -r

这个在查看最近发生的问题时很有用。

配置优化:让journalctl更好用

持久化存储

默认情况下,有些系统的journal日志是存储在内存中的,重启后就丢失了。要启用持久化存储:

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

限制日志大小

编辑/etc/systemd/journald.conf

SystemMaxUse=1G
SystemMaxFileSize=100M

这样可以避免日志占用太多磁盘空间。

常见问题和解决方案

日志查看权限问题

有时候普通用户看不到某些日志,需要加入systemd-journal组:

sudo usermod -a -G systemd-journal username

日志时间显示问题

如果时间显示不对,可能是时区设置问题:

journalctl --utc

使用UTC时间显示。

性能问题

如果journalctl查询很慢,可能是因为日志文件太大。可以考虑:

  1. 清理旧日志
  2. 调整日志级别
  3. 使用更精确的过滤条件

一些小技巧

我平时还会用一些组合命令,比如:

# 查看最近的错误日志,按时间倒序
journalctl -p err -r --since "1 hour ago"

# 查看某个用户的所有日志
journalctl _UID=1000

# 查看系统启动耗时
systemd-analyze blame

还有一个我经常用的别名:

alias jf='journalctl -f'
alias je='journalctl -p err -r'

这样敲命令更快。

有个小细节,journalctl支持tab补全,比如你敲journalctl -u 然后按tab,会自动补全可用的服务名。

与传统日志工具的对比

说实话,journalctl并不是要完全替代grep、awk这些工具,而是在很多场景下提供了更便捷的选择。

传统方法查看nginx错误日志:

tail -f /var/log/nginx/error.log | grep ERROR

用journalctl:

journalctl -u nginx -p err -f

看起来差不多,但journalctl的优势在于:

  • 统一的时间格式
  • 更丰富的过滤选项
  • 不用记住各种日志文件的路径
  • 可以跨重启查看历史日志

当然,对于一些复杂的文本处理,grep、awk、sed这些工具还是不可替代的。我的建议是,先用journalctl快速定位问题范围,然后再用传统工具做精细化分析。

总结

journalctl真的是一个被低估的工具。掌握了它,你的故障排查效率会有质的提升。特别是在现在容器化、微服务架构越来越普及的环境下,能够快速定位问题变得越来越重要。

我建议大家在日常工作中多用用journalctl,慢慢就会发现它的强大之处。不要等到半夜被电话吵醒的时候才想起来有这么个好工具。

当然,工具只是辅助,关键还是要理解系统的运行机制,知道问题可能出现在哪里。journalctl只是帮你更快地找到答案,而不是替你思考。

最后说一句,运维这个工作,工具会越来越先进,但基础的排查思路和对系统的理解永远是最重要的。journalctl只是让我们的工作更轻松一点而已。


如果这篇文章对你有帮助,别忘了点赞转发支持一下!想了解更多运维实战经验和技术干货,记得关注微信公众号@运维躬行录,领取学习大礼包!!!我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习,共同进步!

公众号:运维躬行录

个人博客:躬行笔记

标签: none