这一篇讲什么
出了问题第一件事是看日志,可日志放在哪、重启后还在不在、谁能看,三台机器各不相同。性能那半边,很多「经验值」在新内核上已经不存在了。本篇在三台机器上逐个复现,贴原始输出。
| 机器 | 说明 |
|---|---|
| CentOS 7.9(VMware,4 核 3.7G,3G swap) | 标准装机 |
| Rocky 9.8(LXD 虚拟机,2 核 3.8G,无 swap) | cloud 镜像 |
| Ubuntu 24.04.5(LXD 虚拟机,2 核 3.8G,无 swap) | cloud 镜像 |
1. 日志文件在哪 ------ 三台不一样 ✅
/var/log/ 下 |
CentOS 7 | Rocky 9 | Ubuntu 24.04 |
|---|---|---|---|
messages |
有 | 有 | 没有 |
syslog |
没有 | 没有 | 有 |
secure |
有 | 有 | 没有 |
auth.log |
没有 | 没有 | 有 |
kern.log |
没有 | 没有 | 有 |
cron |
有 | 有 | 没有 |
yum.log / dnf.log |
yum.log | dnf.log | 没有 |
apt/history.log |
没有 | 没有 | 有 |
(Rocky 9 是 cloud 镜像,dmesg、boot.log 两个文件没有,ISO 装机的情况可能不同。)
用 logger 写一条测试日志:
/var/log/messages: 1 (CentOS 7 / Rocky 9)
/var/log/syslog: 1 (Ubuntu 24.04)
三台用 journalctl -t labtest 都能看到。不确定日志在哪,就用 journalctl,它在三台上是一样的。
2. 重启之后,上一次的日志没了 ✅
「服务器半夜重启了,看看重启前发生了什么」:
# journalctl -b -1
Specifying boot ID has no effect, no persistent journal was found (CentOS 7)
Specifying boot ID or boot offset has no effect, no persistent journal was found. (Rocky 9)
原因:
ls: cannot access '/var/log/journal': No such file or directory
/run/log/journal
#Storage=auto
Storage=auto 的意思是「/var/log/journal 目录存在就持久化,不存在就放内存(/run)」。CentOS 7 和 Rocky 9 默认没有这个目录,journal 重启就丢。
Ubuntu 24.04 有这个目录,能看到前几次启动:
-2 ead4f8f6831948fcb12b251d2190cf11 Mon 2026-09-21 14:37:05 UTC Mon 2026-09-21 14:37:43 UTC
-1 f695e303d39a4d9d97fd518789753e52 Mon 2026-09-21 17:08:50 UTC Mon 2026-09-21 17:18:04 UTC
0 2f6d4621567a40b6ba793933f3a239c1 Mon 2026-09-21 17:35:19 UTC Mon 2026-09-21 17:37:24 UTC
CentOS 7 / Rocky 9 要持久化:mkdir -p /var/log/journal && systemctl restart systemd-journald。好在这两台还有 rsyslog 写的 /var/log/messages,重启前的内容在那里面。
3. dmesg:时间看不懂、普通用户看不了 ✅
[ 114.903304] lo: left promiscuous mode
== -T:
[Mon Sep 21 17:36:30 2026] lo: left promiscuous mode
不加 -T 显示的是开机后的秒数,加 -T 换算成时间。
普通用户能不能看:
kernel.dmesg_restrict = 0 (CentOS 7 / Rocky 9,nobody 能读)
kernel.dmesg_restrict = 1 (Ubuntu 24.04)
dmesg: read kernel buffer failed: Operation not permitted
Ubuntu 上普通用户跑 dmesg 会失败 ,要 sudo。
4. 进程突然没了 ------ 被 OOM 杀了 ✅
用 cgroup 把一个 python 进程的内存限制到 50M,让它申请 300M:
退出码=137
137 = 128 + 9,进程是被 SIGKILL 杀的。 程序自己什么日志都来不及写。去内核日志找:
[Mon Sep 21 17:36:44 2026] Memory cgroup out of memory: Killed process 1940 (python3) total-vm:319992kB, anon-rss:50896kB, file-rss:4608kB, shmem-rss:0kB, UID:0 pgtables:168kB oom_score_adj:0
(Rocky 9;Ubuntu 24.04 同样的措辞。)CentOS 7 的措辞是两行:
[Tue Sep 22 01:28:20 2026] Memory cgroup out of memory: Kill process 19830 (python) score 1007 or sacrifice child
[Tue Sep 22 01:28:20 2026] Killed process 19830 (python), UID 0, total-vm:430652kB, anon-rss:51036kB, file-rss:1968kB, shmem-rss:0kB
所以 grep 用 killed process(忽略大小写),三台都能命中 ;journalctl -k 里也有同样的内容。
⚠️ CentOS 7 上还有一个插曲:第一次用 systemd-run -p MemoryLimit=50M 限制,进程没被杀:
分配成功
因为这台有 3G swap,内存超出部分被换到了 swap 上。换成同时限制「内存 + swap」(cgroup v1 的 memory.memsw.limit_in_bytes)才触发 OOM。有 swap 的机器,只限内存不一定会 OOM,而是变慢。
5. logrotate 之后,程序还在往旧文件里写 ✅
一个程序一直往 app.log 追加,用 logrotate 默认的 create 方式轮转:
== create 方式轮转 2 秒后:
0 /var/log/labapp/app.log
16 /var/log/labapp/app.log.1
/var/log/labapp/app.log.1
三台一样。新建的 app.log 是空的,程序还在往 app.log.1 里写 ------ 最后一行是这个进程 1 号文件描述符指向的文件。create 方式是改名 + 新建,程序手里拿的句柄跟着旧文件走了。用 create 方式,程序必须在轮转后重新打开日志文件,否则等于没轮转。
换成 copytruncate:
== copytruncate 方式轮转 2 秒后:
10 /var/log/labapp/app.log
10 /var/log/labapp/app.log.1
先复制、再把原文件清空,程序继续写 app.log,不用程序配合。
调试配置用 -d,只打印不执行:
rotating pattern: /var/log/labapp/app.log 1048576 bytes (3 rotations)
log does not need rotating (log size is below the 'size' threshold)
6. tail -f 盯着日志,轮转后就不动了 ✅
tail -f 和 tail -F 同时盯着 x.log,然后 mv x.log x.log.1,再往新的 x.log 里写 b1、b2:
tail -f 收到:a1
tail -F 收到:a1 b1 b2
三台一样。-f 跟的是文件句柄,文件被改名后它还盯着旧文件;-F 跟的是文件名 ,会重新打开。看线上日志用 tail -F。
7. free:available 才是能用的内存 ✅
清掉缓存,然后读一遍 400M 的文件:
total used free shared buff/cache available
Mem: 3899 331 3651 12 87 3567
== 读过 400M 文件后:
total used free shared buff/cache available
Mem: 3899 391 3241 12 497 3507
(Rocky 9,单位 MB。)free 少了 410M,available 只少了 60M。CentOS 7 是 3415 → 3341,Ubuntu 是 3548 → 3528。buff/cache 里的内存需要时可以还回来,看剩多少内存看 available,别看 free。
8. iowait:CPU 空着,机器却很卡 ✅
4 个 dd oflag=direct(绕过缓存直接写盘)同时跑 20 秒:
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 4 0 3659996 3624 91296 0 0 4 1038336 1978 2101 0 15 0 85 0
0 4 0 3661004 3660 91368 0 0 4 1021952 2022 2113 1 15 3 81 0
%Cpu(s): 3.0 us, 18.2 sy, 0.0 ni, 33.3 id, 45.5 wa, 0.0 hi, 0.0 si, 0.0 st
dd 进程状态:
4 D
(Rocky 9。)看三个地方:
vmstat的wa(等 IO 的 CPU 时间)到了 85;b列(阻塞在 IO 上的进程数)是 4;- 进程状态
D(不可中断睡眠,在等磁盘)的进程有 4 个。
Ubuntu 24.04 的 wa 是 83/84,top 里 78.3。CentOS 7 的 wa 只有 31/32,dd 进程 1 个 D、3 个 R(机器和磁盘虚拟化方式都不同,数值不能横比,只看同一台上 wa 升没升)。
⚠️ 压测磁盘一定限制写入量(这里每个 dd 循环覆盖写同一个 1G 文件),并确认清理动作真的执行了。
9. 单核跑满,总 CPU 只显示 25% ✅
一个 yes 进程:
Average: CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
Average: all 24.50 0.00 0.75 0.00 0.00 0.00 0.00 0.00 0.00 74.75
Average: 0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
Average: 1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
Average: 2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00
Average: 3 98.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
(CentOS 7,4 核。)总体只用了 24.5%,但 3 号核已经满了。单线程程序卡死时,看总 CPU 永远觉得「还有富余」,要 mpstat -P ALL 看每个核。
10. sysstat:装了也不一定在采集 ✅
mpstat、iostat、sar 都在 sysstat 包里,三台默认都没装。装上之后:
enabled
inactive
/var/log/sa (CentOS 7 / Rocky 9)
disabled
inactive
/var/log/sysstat
ENABLED="false" (Ubuntu 24.04)
Rocky 9 靠 sysstat-collect.timer 定时采集;Ubuntu 装完默认不采集 ,要把 /etc/default/sysstat 里的 ENABLED 改成 "true"。否则等到出事想用 sar 看历史数据时,什么都没有。
11. limits.conf 改了,服务的 ulimit 没变 ✅
在 /etc/security/limits.d/ 里写:
* soft nofile 12345
* hard nofile 23456
然后分别看登录 shell 和 systemd 服务:
systemd 服务:Max open files 1024 4096 files (CentOS 7)
systemd 服务:Max open files 1024 524288 files (Rocky 9 / Ubuntu 24.04)
su - 登录 shell:12345 23456 (CentOS 7 / Rocky 9)
su - 登录 shell:1024 1048576 (Ubuntu 24.04)
两个结论:
-
limits.conf 对 systemd 启动的服务无效 ------ 它是 PAM 在登录时设置的,服务不经过登录。要在 unit 里写
LimitNOFILE:加 LimitNOFILE=65536 后:Max open files 65536 65536 files
-
Ubuntu 上
su -切到 root 也没吃到这个配置(推测:*通配符不作用于 root,或 Ubuntu 的 su 没启用 pam_limits,未查证)。不管哪台,改完都要用实际启动方式验证一次 ,别只在自己的 shell 里ulimit -n。
12. 网上的内核参数「优化」,有的已经不存在了 ✅
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 0
net.core.somaxconn = 128 (CentOS 7)
sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory
net.ipv4.tcp_tw_reuse = 2
net.core.somaxconn = 4096 (Rocky 9 / Ubuntu 24.04)
tcp_tw_recycle在新内核里已经删了。 照抄老教程把它写进/etc/sysctl.conf,在 Rocky 9 / Ubuntu 24.04 上就会碰到上面这个cannot stat。somaxconn新内核默认已经是 4096,CentOS 7 还是 128。netstat -s三台都没有,用nstat代替。
小结
| 现象 | 实际情况 |
|---|---|
重启后 journalctl -b -1 报错 |
CentOS 7 / Rocky 9 没有 /var/log/journal,journal 不持久 |
| Ubuntu 普通用户 dmesg 报错 | dmesg_restrict = 1 |
| 进程退出码 137 | 被 SIGKILL,去 dmesg 找 killed process |
| 限了内存却没 OOM | 有 swap,要连 swap 一起限 |
| 轮转后新日志是空的 | create 方式,程序还在写 .1 |
| tail 轮转后不动 | 用 -F |
| CPU 空闲机器却卡 | 看 wa、b 列和 D 状态 |
| 总 CPU 25% 程序却卡死 | 单核满了,mpstat -P ALL |
| 想用 sar 看历史却没数据 | Ubuntu 默认 ENABLED="false" |
| limits.conf 对服务无效 | 在 unit 里写 LimitNOFILE |
下一篇:用户与权限 ------ useradd 在 Ubuntu 上不建家目录、sudoers 写错一个文件 sudo 全挂、SGID 共享目录为什么还是不够。