1. 从一次“假报警”说起:系统管理笔记的由来
做 Red Hat 系运维久了,你会发现一个规律:真正把系统搞挂的,往往不是某个高深的内核参数,而是那些文档里一笔带过、日常没人搭理的细节问题。上个月值班,一台运行 PostgreSQ L 的生产服务器突然 load average 飙到 30,但 top 里 CPU 和内存都显示“一切正常”,业务方却在群里炸了锅。我登上去翻了半天日志,最后在 /var/log/messages 里发现每秒钟几百条 oom-killer 记录,原来是日志因为磁盘满被迫写入了内存 tmpfs,而 tmpfs 吃光了内存,触发了内核的 OOM 机制——一个典型的日志、磁盘、内存三个子系统纠缠在一起的连环故障。
这件事让我下定决心把手头关于日志分析、性能调优、SELinux 策略配置和存储管理的零散笔记整理成体系。这些内容单独看都不算难,但组合在一起,就是一台 Red Hat 服务器从“能跑”到“跑得稳、扛得住、还算安全”的全部底子。这篇文章里所有操作都在 RHEL 8/9(以及兼容的 Rocky Linux、AlmaLinux)上实测过,命令差异不大,CentOS 7 偶尔会有个别包名不同,我在关键地方会标注出来。
不管你是刚接手服务器的新手,还是已经在生产环境摸爬滚打几年的老手,这篇笔记的价值在于:不只告诉你命令怎么写,还告诉你踩过的坑在哪里、为什么这个参数要这么调、日志里哪些信息是烟雾弹哪些才是真信号。下面我们按四个主题逐一拆开聊。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 日志分析不玄学:从日志格式到故障现场的完整链路
日志分析被不少人说得神乎其神,仿佛掌握了什么“玄机”就能未卜先知。实际上,日志分析的底层逻辑就一句话:把系统的行为按时间线还原出来,找到第一个最不像“正常”的记录。 难点从来不在工具,而在于你知不知道每个组件的日志长什么样、正常状态是什么样。
2.1 日志格式里藏着的信息层级
Red Hat 系统里日志主要走两个阵营:传统的 syslog 体系(在 RHEL 8 之后由 rsyslog 接管)和 systemd 的 journald 体系。很多人一上来就 journalctl -xe,其实这两个体系是可以协同工作的,前提是你了解它们的边界。
rsyslog 的日志文件本体是明文文本,每个字段都靠空格和冒号分隔。以 /var/log/messages 里最常见的一行为例:
code复制Jun 28 14:32:17 hostname kernel: [12345.678901] Out of memory: Killed process 1234 (postgres) total-vm:1234567kB, anon-rss:890123kB, file-rss:0kB
拆开看是五层信息:
- 时间戳(
Jun 28 14:32:17)——注意它不带年份,所以跨年排查日志时务必先确认文件是否做过 logrotate 归档; - 主机名(
hostname)——在集中式日志收集场景下,这是区分来源的关键; - 产生日志的模块(
kernel)——代表内核消息,同理还有systemd、NetworkManager、sudo等; - 内核时间戳(
[12345.678901])——这是内核自己的滴答计数,对不上墙钟时间很正常,但在分析内核 panic 或 oom 顺序时非常有用; - 日志正文——真正的信息所在,但也是最容易被误读的部分。
journald 体系则不同,它把这些字段结构化存储了。journalctl 你可以用 -o verbose 查看完整字段,比如 _PID、_COMM、_EXE、SYSLOG_IDENTIFIER 等。这在做关联分析时很贴心——一条日志不再是一行字符串,而是可以用字段过滤的一条记录。但要注意,journald 日志默认是易失的,如果没做持久化,重启后就查不到历史日志了。RHEL 8 开始默认把 journal 写到 /run/log/journal/(tmpfs),想要持久化,得手动创建 /var/log/journal/ 目录:
bash复制mkdir -p /var/log/journal
systemctl restart systemd-journald
2.2 故障定位的实操顺序:先看时间窗,再找异常指纹
真正的日志排查不是从头到尾读文件,而是先锁定时间窗,再找异常指纹。拿开头的 OOM 故障举例子,当时我的操作顺序是:
- 先用
uptime确认负载异常的起始时间点; - 用
journalctl --since "2024-06-28 14:30:00" --until "2024-06-28 14:35:00" -k拉取该时间窗的内核日志,确认是不是内核级事件; - 再用
journalctl --since ... --until ... -u postgresql拉取同一时间窗的 PostgreSQL 服务日志,对比两边的时间线。
这一套下来,OOM 的发生时间和 PostgreSQL 开始报错的时间精确到秒级对齐,问题就锁定了。之所以强调时间窗,是因为系统在故障发生时往往在同一时间段产生几十种不同类型的日志,没有时间窗概念很容易被噪音带偏。journalctl 的时间语法兼容 YYYY-MM-DD HH:MM:SS,也支持 yesterday、-1h 这种相对时间,实际操作中非常实用。
再分享一个我常用的“异常指纹”概念。日志里的错误五花八门,但真正值得关注的错误通常带有几个典型特征:短时间内同一错误重复出现(循环报错)、多个不同模块在同一时间点报类似错误(级联故障)、错误信息里包含进程名和资源数值(资源耗尽型故障)。对应地,我用三个小命令就能快速定位:
bash复制# 统计当前时间窗内最频繁出现的前20条日志
journalctl --since "-1h" | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20
# 只看内核级错误
journalctl -k -p err -b
# 只看某个服务最近的异常
journalctl -u nginx.service --since "-1h" -p warning
-p 参数控制日志级别过滤,级别从 emerg、alert、crit、err、warning、notice、info 到 debug 递减,实际生产环境建议日常看 warning 以上,排查问题时再下调到 info。级别太低,日志量会爆炸,反而找不到重点。
2.3 ELK 不是银弹,但集中分析确实能治“找日志”的命
当服务器数量超过三五台,逐台登录翻日志就变成了体力活。ELK(Elasticsearch + Logstash + Filebeat + Kibana)这类方案的价值在于把日志集中到一个地方,用统一的查询语言做全文检索。但在上手 ELK 之前,我想泼一盆冷水:如果你连单机日志怎么分析都还没搞清楚,上 ELK 只会得到一堆检索不到的索引。 日志分析的核心永远是“你要找什么”,工具只是加速这个过程。
在 Red Hat 上部署 Filebeat 作为日志采集端是比较常见的轻量方案。以 RHEL 9 为例,安装和配置核心逻辑大概是这样的:
bash复制# 添加 Elastic 官方仓库(以 8.x 为例)
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
cat > /etc/yum.repos.d/elastic.repo <<'EOF'
[elastic-8.x]
name=Elastic repository for 8.x packages
baseurl=https://artifacts.elastic.co/packages/8.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
