Systemd 吃掉 7.4GB 内存?测试环境的一次意外发现

🚨 惊魂时刻:当你发现 systemd 进程占用了 7.4GB 内存时,第一反应是:“我是不是看错了?”

作为一名在 Linux 系统运维一线摸爬滚打多年的工程师(是的,打杂的娃头衔就是这么多变),我以为自己见过各种奇葩问题。直到那个平静的周三早晨,我在进行日常系统巡查时,发现测试环境服务器的内存使用异常——系统内存使用率居然达到了 65%!

当我登录服务器查看 top 命令时,看到的景象让我大吃一惊:systemd 进程竟然吃掉了 7.4GB 内存!要知道,这个家伙平时安安静静地只用几十兆内存,现在却成了内存大胃王。

虽然这只是测试环境,但这个问题给了我们一个重要警示:如果同样的问题发生在生产环境,后果可能不堪设想。这次的排查经历不仅解决了当前问题,更为生产环境的部署和运维策略提供了宝贵的参考价值。


目录

  1. 故事背景:周三早晨的例行巡查
  2. 第一反应:这不科学!
  3. 开始侦探工作:一步步缩小包围圈
  4. 真相大白:内存泄漏这个老朋友
  5. 救火队出动:解决方案登场
  6. 未雨绸缪:如何预防类似问题
  7. 收工总结:这次踩坑学到了什么

1. 故事背景:周三早晨的例行巡查

先交代一下案发现场的基本情况,毕竟知己知彼才能百战不殆嘛。

我们的受害者是一台运行 AlmaLinux 10.0 的服务器,这可是个挺新的发行版,按理说不应该有什么古怪问题。

cat /etc/os-release

详细的身份信息

NAME="AlmaLinux"
VERSION="10.0 (Purple Lion)"
ID="almalinux"
ID_LIKE="rhel centos fedora"
VERSION_ID="10.0"
PLATFORM_ID="platform:el10"
PRETTY_NAME="AlmaLinux 10.0 (Purple Lion)"
ANSI_COLOR="0;34"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:almalinux:almalinux:10::baseos"
HOME_URL="https://almalinux.org/"
DOCUMENTATION_URL="https://wiki.almalinux.org/"
VENDOR_NAME="AlmaLinux"
VENDOR_URL="https://almalinux.org/"
BUG_REPORT_URL="https://bugs.almalinux.org/"

ALMALINUX_MANTISBT_PROJECT="AlmaLinux-10"
ALMALINUX_MANTISBT_PROJECT_VERSION="10.0"
REDHAT_SUPPORT_PRODUCT="AlmaLinux"
REDHAT_SUPPORT_PRODUCT_VERSION="10.0"
SUPPORT_END=2035-06-01

💡 小插曲:AlmaLinux 是 CentOS 的后继者之一,有着到 10 年的长期支持,算是挺靠谱的企业级发行版。


2. 第一反应:这不科学!

周三上午 9:30,我照例开始进行服务器集群的日常巡查。这是我们团队的标准流程:每天早上检查一遍所有环境的健康状况,包括开发、测试、预发布等各个环境,确保各个团队都能正常工作。

当我打开监控面板时,一个异常的数字引起了我的注意:

🚨 测试服务器内存使用率: 65% (正常应该在 30% 左右)

我立即 SSH 连接到服务器,第一时间就是看 top 命令,然后我就愣了:

$ top
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0  7.3g   7.4g   ??? S   2.1 46.3  12:34.56 systemd

7.4GB???

我揉了揉眼睛,再看一遍。没错,systemd 这个家伙真的吃了 7.4GB 内存

😱 心理活动:我的第一反应是"难道我看错了?“,然后是"难道服务器被黑了?”,接着是"难道 systemd 进化了?"

要知道,systemd 作为系统的 1 号进程,平时就是个安安静静的管家,顶多用个几十 MB 内存。现在突然变成了内存大胃王,这不是要命嘛!


3. 开始侦探工作:一步步缩小包围圈

冷静下来之后,我开始像个侦探一样分析这个异常现象。既然 systemd 占用了这么多内存,那肯定有原因,我们一个个排查。

3.1 嫌疑人一号:进程内存分析

首先,我要确认这个数字是不是真的。有时候 top 命令会有误报,所以我直接去 /proc 目录下看第一手资料:

cat /proc/1/status | grep -E 'VmRSS|VmSize'

结果更加残酷:

VmSize:   7433836 kB  # 虚拟内存大小:~7.3 GB
VmRSS:    7424676 kB  # 实际物理内存:~7.4 GB

😨 更惊恐的发现:虚拟内存和实际物理内存几乎一样大!这说明这 7.4GB 不是虚张声势,而是实实在在被占用了。

这下我心里更慌了。如果是虚拟内存大但实际内存小,还可能是内存映射的问题。现在连 RSS 都这么大,说明这些内存是真的被 systemd 给霸占了。

3.2 嫌疑人二号:日志系统是不是搞鬼了

我的第二个怀疑对象是 journald。这家伙负责收集系统日志,如果日志爆炸了,确实可能导致内存使用异常。

# 看看日志到底占了多少空间
journalctl --disk-usage

# 再仔细检查一下具体目录
du -sh /run/log/journal/*

结果让我松了一口气:

Archived and active journals take up 415.9M in the file system.
416M    /run/log/journal/d97bb41f000843d19865fcf40fed142b

🤔 推理过程:416MB 的日志文件绝对解释不了 7.4GB 的内存占用。即使 journald 把日志全部加载到内存里,也不可能有这么大的差距。

看来日志系统是清白的,继续找下一个嫌疑人。

3.3 嫌疑人三号:会不会是版本太老了

第三个怀疑对象就是 systemd 本身的版本问题。有些老版本的软件确实会有内存泄漏的 bug。

systemctl --version

版本信息显示:

systemd 257 (257-9.el10_0.1.alma.1-g1905557)

💭 分析思路:systemd 257 是一个相当新的版本,发布时间不久,按理说不应该有这种低级的内存泄漏问题。而且如果是版本 bug,网上应该已经有一堆人在抱怨了。

到这里,三个主要嫌疑人都被排除了,看来这个案子没有那么简单…


4. 真相大白:内存泄漏这个老朋友

经过一番排查,所有常见的嫌疑人都被排除了。这时候,一个更加阴险的可能性浮现在我脑海里:内存泄漏

🕵️ 福尔摩斯时刻:当你排除了所有不可能的情况,剩下的即使再不可思议,也必然是真相。

分析到这里,情况已经很明朗了:

被排除的无辜群众

  • ❌ 日志文件过大(人家只有 416 MB,很乖的)
  • ❌ 版本太老(257 版本挺新的,不背这个锅)
  • ❌ 配置有问题(检查了一圈都正常)

真正的罪魁祸首

  • systemd/journald 内存泄漏:内部某个地方在偷偷囤积内存
  • 内存管理 bug:分配了内存却忘记释放

💡 技术分析:systemd 在处理系统事件、服务状态变化、日志记录等操作时,由于某个内部 bug,导致分配的内存没有正确释放。时间一长,这些"僵尸内存"就越积越多,最终变成了 7.4GB 的庞然大物。

说白了,就是 systemd 得了"健忘症",只记得要内存,忘记了还内存。(其实,我也只是怀疑,没有更确切的证据)


5. 救火队出动:解决方案登场

5.1 先救命:一招制敌

现在服务器内存快爆了,必须先解燃眉之急。对于这种内存泄漏问题,有一个简单粗暴但非常有效的方法:

sudo systemctl daemon-reexec

🎯 这招的精髓:让 systemd 重新执行自己,相当于给它做了个"内存重置",但又不会影响正在运行的服务。

为什么这招管用

  • 重置进程状态:清空所有累积的内存垃圾
  • 保持服务连续性:不会杀死其他系统服务
  • 立竿见影:几秒钟就能看到效果

我忐忑不安地敲下这个命令,然后迅速查看内存使用:

$ top
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0   47m    32m   ??? S   0.1  0.4   0:02.15 systemd

奇迹发生了! 从 7.4GB 瞬间降到了 32MB,systemd 又变回了那个安静的小透明。

救火成功:内存使用率从 65% 降到了 18%,系统恢复正常。我长长地舒了一口气。

5.2 再治本:长期防护措施

虽然 daemon-reexec 解决了燃眉之急,但我们不能每次都靠这种"重启大法"。要想从根本上预防这种问题,还需要做一些长期的防护工作。

5.2.1 给 journald 戴上"紧箍咒"

虽然这次不是 journald 的锅,但既然 systemd 家族容易出问题,我们就给日志系统也设个限制,防患于未然:

sudo vi /etc/systemd/journald.conf

防护配置

[Journal]
# 日志磁盘使用上限
SystemMaxUse=500M
# 内存使用上限  
RuntimeMaxUse=200M
# 单个日志文件大小限制
SystemMaxFileSize=50M
# 日志保留时间(别让古董日志堆积)
MaxRetentionSec=1month

设置完后重启一下 journald:

sudo systemctl restart systemd-journald

💡 设计思路:即使以后 journald 也"健忘"了,最多也就占用 200MB 内存,翻不起大浪。

5.2.2 开启内存监控功能

为了以后能更好地监控各个服务的内存使用,我们开启 systemd 的内存统计功能:

sudo vi /etc/systemd/system.conf

监控配置

[Manager]
# 开启内存统计(知己知彼)
DefaultMemoryAccounting=yes
# 顺便开启 CPU 统计
DefaultCPUAccounting=yes

让配置生效:

sudo systemctl daemon-reexec

这样以后就可以用 systemctl status 看到每个服务的详细资源使用情况了。

5.2.3 系统更新策略

既然这是测试环境,我们可以放心地进行系统更新来修复这个 bug:

# 专门更新 systemd
sudo dnf update systemd

# 全系统更新
sudo dnf update

🔄 测试环境 vs 生产环境

  • 测试环境:可以积极更新,验证补丁效果
  • 生产环境:应该谨慎更新,优先通过配置和监控来规避风险

这次在测试环境发现问题,给了我们宝贵的时间来制定生产环境的应对策略。


6. 未雨绸缪:如何预防类似问题

经历了这次测试环境的意外发现,我深深意识到:预防比治疗更重要。更关键的是,我们需要为生产环境制定相应的防护策略,避免类似问题在生产环境中出现。

6.1 智能监控脚本:会自救的系统

我写了一个小脚本,让它定期检查 systemd 的内存使用,一旦发现异常就自动执行 daemon-reexec。相当于给系统配了个"自动医生"。

sudo vi /usr/local/bin/systemd-memory-monitor.sh

"自动医生"脚本

#!/bin/bash
# systemd 内存监控与自动修复脚本
# 设计目标:测试环境自动化,为生产环境提供参考

# 配置参数
RSS_LIMIT_MB=512  # 内存报警阈值:512 MB
LOG_FILE="/var/log/systemd-memory-monitor.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

# 获取 systemd 当前内存使用(单位:MB)
RSS_KB=$(awk '/VmRSS/{print $2}' /proc/1/status)
RSS_MB=$((RSS_KB / 1024))

# 记录日常体检结果
echo "$DATE - systemd 内存体检: ${RSS_MB}MB" >> "$LOG_FILE"

# 如果内存使用超标,立即处理
if [ "$RSS_MB" -gt "$RSS_LIMIT_MB" ]; then
    echo "$DATE - [🚨 警报] systemd 内存异常: ${RSS_MB}MB (超过阈值 ${RSS_LIMIT_MB}MB)" >> "$LOG_FILE"
    echo "$DATE - [💊 治疗] 执行 systemctl daemon-reexec 自动修复" >> "$LOG_FILE"
    
    # 执行自动修复
    systemctl daemon-reexec
    
    # 等待几秒让系统稳定
    sleep 5
    
    # 检查治疗效果
    NEW_RSS_KB=$(awk '/VmRSS/{print $2}' /proc/1/status)
    NEW_RSS_MB=$((NEW_RSS_KB / 1024))
    echo "$DATE - [✅ 结果] 修复后内存使用: ${NEW_RSS_MB}MB" >> "$LOG_FILE"
    
    # 发送系统通知(这样就能在系统日志里看到)
    logger "systemd-auto-doctor: 发现内存异常(${RSS_MB}MB),自动修复完成,当前使用: ${NEW_RSS_MB}MB"
fi

给脚本加上执行权限:

sudo chmod +x /usr/local/bin/systemd-memory-monitor.sh

6.2 定时体检:让系统自己照顾自己

然后我用 systemd 的 timer 功能,让这个"自动医生"每 5 分钟检查一次:

创建服务文件

sudo vi /etc/systemd/system/systemd-memory-monitor.service
[Unit]
Description=Systemd Memory Auto Doctor
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/systemd-memory-monitor.sh
User=root
StandardOutput=journal
StandardError=journal

创建定时器

sudo vi /etc/systemd/system/systemd-memory-monitor.timer
[Unit]
Description=每5分钟进行systemd内存体检
Requires=systemd-memory-monitor.service

[Timer]
OnBootSec=5min        # 开机5分钟后开始
OnUnitActiveSec=5min  # 每5分钟执行一次
AccuracySec=1min      # 时间精度1分钟

[Install]
WantedBy=timers.target

启动自动医生

sudo systemctl daemon-reload
sudo systemctl enable systemd-memory-monitor.timer
sudo systemctl start systemd-memory-monitor.timer

这样,在测试环境中,即使 systemd 再次"健忘",系统也能自己发现并自动修复。

💡 分层防护策略

  • 测试环境:积极的自动化修复,快速验证解决方案
  • 生产环境:保守的监控告警,人工干预确保安全

测试环境的自动化实践为生产环境的部署策略提供了宝贵的经验。


7. 收工总结:这次踩坑学到了什么

回顾这整个惊心动魄的故障处理过程,虽然过程有点刺激,但收获还是很大的。让我来总结一下这次踩坑的经验教训。

7.1 故障处理心得

🎯 核心经验:冷静分析 + 排除法 + 快速止损 + 长期预防

诊断三步曲

  1. 先救命systemctl daemon-reexec 让系统快速恢复
  2. 找真凶:通过 /proc/1/status 精确定位内存使用
  3. 除后患:建立监控和自动化处理机制

我学到的排查套路

  • 数据说话:不要凭感觉,要用具体的数字和日志
  • 排除法:一个个排除可能的原因,缩小包围圈
  • 先止损再分析:生产环境故障时,先恢复服务再深入分析

7.2 运维哲学思考

这次事件让我重新思考了一些运维理念:

“测试环境的价值”

  • 测试环境不只是用来跑功能测试,也是发现系统问题的重要阵地
  • 在测试环境发现问题比在生产环境发现问题要幸运得多
  • 测试环境的问题处理经验直接指导生产环境的预防策略

“分层防护理念”

  • 测试环境可以激进一些,快速验证解决方案
  • 生产环境必须保守一些,稳定性优于一切
  • 好的运维策略是在稳定性和效率之间找到平衡

7.3 实用经验清单

给遇到类似问题的兄弟们一个可以直接抄作业的清单:

步骤命令/操作用途
确认问题cat /proc/1/status | grep VmRSS精确测量内存使用
排除日志journalctl --disk-usage检查日志文件大小
检查版本systemctl --version确认是否为已知bug版本
应急修复systemctl daemon-reexec无损重置systemd内存
长期预防配置监控脚本自动发现和修复

7.4 最后的思考

💭 感悟时刻:每一次故障都是系统在教我们如何变得更强。

这次 systemd 内存泄漏事件,让我意识到:

  • 测试环境的重要性:它是发现问题的第一道防线,为生产环境提供预警
  • 分层思维的价值:测试环境和生产环境的处理策略应该有所不同
  • 问题的传递性:测试环境的问题往往预示着生产环境的潜在风险
  • 预防的经济性:在测试环境解决问题比在生产环境解决问题成本低得多

🔥 最重要的领悟:真正的运维价值不在于避免所有问题,而是在于建立有效的问题发现和处理机制,让问题在最合适的环境中被解决。

希望我的这次测试环境问题排查经历能给大家一些启发。测试环境的每一个问题,都是生产环境稳定运行的保障!


💡 写在最后:如果你也遇到了类似的 systemd 内存问题,记得先用 daemon-reexec 救急,然后建立监控机制。有问题欢迎交流讨论!

👋 作者信息:码农秋 | 发布日期:2025-08-27 | 一个热爱分享的全栈架构师

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值