AlmaLinux系统宕机卡死怎么办从CPU满载内存溢出到网络断连的常见故障排查与修复方法详解
系统突然疯了?先别慌
你可能遇到过这种场景:服务器上跑得好好的程序,突然就卡住了,SSH连不上,ping也不通了,或者连上了但命令行动都不动,光标在那儿傻等。这种时候,很多刚接触Linux运维的朋友第一反应是”完了,又要重装了”。
其实不是的。AlmaLinux作为一个企业级的RHEL替代系统,和Rocky Linux一样继承了Red Hat生态的稳定性基因,但和任何操作系统一样,它也会因为资源耗尽、配置错误或硬件故障而出现问题。关键是你能否快速定位根因,而不是盲目重启。
今天这篇文章,我就带你从最实际的场景出发,把AlmaLinux最常见的几种”发疯”状态——CPU满载、内存溢出、网络断连、IO阻塞、内核恐慌——逐个拆开来讲。我会给出具体的排查命令、日志位置、常见原因和修复方案,让你遇到这些问题时能有一个清晰的思路,而不是对着黑屏发愣。
先看一眼——系统还”活着”吗
在深入任何故障之前,有一个问题必须先确认:系统是真的卡死了,还是只是网络层不响应?
这听起来很基础,但很多新手会在这里走弯路。比如SSH连不上,就直接判定系统宕机,然后去机房强行断电重启。但实际上,可能只是网络模块出了问题,或者防火墙规则被意外修改了。
先试试这几个方法:
# 方法1:ping多个节点,排除本地网络问题
ping -c 5 8.8.8.8
ping -c 5 $(hostname -I | awk '{print $1}')
# 方法2:尝试其他端口,比如HTTP服务是否还在响应
curl -I http://localhost
curl -I https://localhost
# 方法3:如果有带外管理(IPMI/iDRAC/iLO),直接连接控制台
# 这是最可靠的判断方式,不受网络影响
# 方法4:尝试Telnet到常见端口
telnet localhost 22
telnet localhost 80
telnet localhost 443
如果ping不通网关,但本地回环(127.0.0.1)正常,说明问题大概率在网络栈或网卡配置上。如果回环也不通,那才是真正”死透”了。
这里有一个我亲自遇到的案例。有一台AlmaLinux 9的服务器,客户反映网站打不开了。跑到机房一看,电源正常,系统指示灯正常。SSH连不上,Web也连不上。我首先用IPMI连接虚拟控制台,发现系统还在运行,终端有输出,只是没有任何入站连接能进来。最后发现是nftables规则被一个自动化脚本改坏了,把所有入站流量都DROP掉了。这种问题,重启一万次也解决不了,必须找到根因。
CPU满载——谁在偷走你的算力
CPU满载是最常见的系统卡顿原因之一。当CPU使用率达到100%时,所有进程都会被迫等待调度,系统响应会越来越慢,最终看起来就像死了一样。
快速定位”罪魁祸首”
# 方法1:用top看整体情况(按CPU排序)
top
# 方法2:更详细的进程级CPU监控
ps aux --sort=-%cpu | head -20
# 方法3:看哪个CPU核心负载最高
mpstat -P ALL 1 5
# 方法4:如果是容器环境,看哪个容器最吃CPU
docker stats --no-stream
# 或者Podman
podman stats --no-stream
# 方法5:查看CPU使用历史,确认是突发还是持续
sar -u 1 10
top命令的输出里,重点关注这几个字段:
- %CPU:进程占用的CPU百分比,超过100%说明是多核多线程在跑
- PID:进程ID,后面杀进程要用
- COMMAND:进程名,初步判断是什么程序在搞事
- S列:状态,
R表示正在运行,D表示不可中断的IO等待(这个要小心)
常见 culprit 和对应处理
1. runaway进程(失控的循环或计算)
# 先用top确认PID,然后查看它的完整信息
ps -fp <PID> -o pid,ppid,cmd,etime,pcpu,pcpu
# 查看进程打开了哪些文件(判断它在做什么)
lsof -p <PID>
# 如果是可疑进程,先看它的命令行参数和环境
cat /proc/<PID>/cmdline | tr '\0' ' '
cat /proc/<PID>/environ | tr '\0' '\n'
# 确认无害后再考虑处理
kill -15 <PID> # 先尝试正常终止
kill -9 <PID> # 实在不行再强制杀
我见过最离谱的一个案例:某个Python脚本因为逻辑bug进了无限循环,CPU占满了一整个核心,跑了三个月才被运维发现。服务器上只跑了一个数据处理任务,但那个任务每隔一秒就要把整个数据库重新扫一遍。这种问题用ps看命令行参数就能发现,是python3 /opt/data/processor.py --loop,一眼就能看出问题。
2. 挖矿病毒
# 检查可疑进程
ps aux | grep -E 'xmrig|minerd|cpuminer|cryptonight'
# 检查可疑的启动项
systemctl list-unit-files | grep enabled
ls -la /etc/systemd/system/
ls -la /etc/rc.local 2>/dev/null
# 检查crontab里有没有奇怪的任务
crontab -l
ls -la /etc/cron.d/
ls -la /var/spool/cron/
# 检查是否有奇怪的 systemd 服务
systemctl list-units --type=service --state=running | grep -vE '(systemd|network|sshd|postfix|docker|polkit|dbus)'
如果怀疑是挖矿病毒,一定要先做证据保留,不要急着杀进程:
# 保留进程信息
ps auxf > /tmp/process_dump.txt
# 保留网络连接
netstat -tlnp > /tmp/netstat_dump.txt
# 保留系统日志
journalctl --since "2 hours ago" > /tmp/journal_dump.txt
# 然后才开始清理
挖矿产生的进程通常会修改启动项或crontab来实现持久化。清理的时候一定要把源头一起干掉,否则重启之后又会冒出来。
3. 中断风暴(IRQ Balance问题)
# 查看中断分布是否均衡
cat /proc/interrupts
# 检查irqbalance服务是否运行
systemctl status irqbalance
# 如果某个CPU核的中断数异常高,尝试重新平衡
systemctl restart irqbalance
# 查看具体哪个中断来源占用了大量CPU
sar -I ALL 1 5
中断风暴在虚拟化环境(尤其是KVM虚拟机)里比较常见。当虚拟化层的中断处理集中在某个CPU核心上时,那个核心就会跑满,而其他核心却很空闲。这种情况top看起来可能不像是进程占CPU,而是%sys或%irq很高。
4. 内核线程异常
# 查看内核线程的CPU占用
ps -eLf | awk '$1 == "root" {print}' | head -30
# 特别注意kworker进程
ps aux | grep kworker
kworker是内核工作线程,正常情况下不应该占用太多CPU。如果某个kworker进程长期占满CPU,通常是某个内核模块出了问题。可以用dmesg看看最近的内核日志:
dmesg -T | tail -50
CPU满载的预防
# 使用cgroup限制进程CPU使用
# 比如限制某个服务的CPU不超过50%
systemctl set-property myservice.service CPUQuota=50%
# 或者用ulimit限制
echo "* hard nproc 1024" >> /etc/security/limits.conf
echo "* soft nproc 1024" >> /etc/security/limits.conf
# 安装并配置监控告警
# AlmaLinux默认有cockpit,网页端可以看到CPU趋势
# 也可以用简单的脚本告警
cat > /usr/local/bin/cpu_alert.sh << 'EOF'
#!/bin/bash
LOAD=$(cat /proc/loadavg | awk '{print $1}')
if (( $(echo "$LOAD > $(nproc)" | bc -l) )); then
echo "CPU load alert: $LOAD on $(hostname)" | mail -s "CPU Alert" admin@example.com
fi
EOF
chmod +x /usr/local/bin/cpu_alert.sh
内存溢出——OOM killer何时降临
内存问题是另一个让系统”说没就没”的原因。当物理内存和交换空间都耗尽时,Linux内核会启动OOM killer(Out of Memory Killer),随机或者按策略杀死占用内存最多的进程来释放空间。这个过程对用户来说就是:某个进程突然消失,或者系统卡死不动。
判断是否内存不足
# 方法1:看内存概览
free -h
# 方法2:更详细的内存信息
cat /proc/meminfo
# 方法3:查看每个进程的内存使用
ps aux --sort=-%mem | head -20
# 方法4:查看cgroup级别的内存使用(容器环境必看)
cat /sys/fs/cgroup/memory/memory.usage_in_bytes
# 或者用systemd的memory统计
systemctl status | grep -E 'memory|Memory'
free -h的输出里,重点关注:
- available:真正可用的内存,不是free(free包含被缓存占用但可回收的部分)
- buff/cache:内核缓冲和页缓存,正常情况下这部分会在需要时自动释放
- swap used:如果swap使用量持续增长,说明系统已经在用磁盘当内存,性能会急剧下降
有一个常见的误解:看到free很少就以为内存不够了。实际上在Linux里,free少不一定是坏事,只要available还够就行。内核会把空闲内存拿来缓存文件和页数据,加速I/O。真正危险的是available也很低,同时swap使用量在飙升。
OOM事件追踪
# 查看内核日志中的OOM记录
dmesg -T | grep -i "out of memory"
dmesg -T | grep -i "oom-killer"
# 查看完整的journal日志
journalctl -k --grep="oom" --since "24 hours ago"
# 如果系统已经重启过了,看之前的日志
journalctl -b -1 --grep="oom"
# 查看OOM killer杀死了哪些进程
grep -r "oom_kill" /var/log/
典型的OOM日志长这样:
[12345.678901] Out of memory: Killed process 1234 (java) total-vm:8388608kB, anon-rss:4194304kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:8192kB oom_score_adj:0
从这行日志里你能看到:
- 被杀的进程名和PID
- 虚拟内存大小(total-vm)
- 实际物理内存占用(anon-rss)
- 进程的OOM分数(oom_score_adj),这个值越大越容易被杀
内存泄漏的排查
有些进程会慢慢吃掉所有内存,这就是内存泄漏。最常见的情况是Java应用。
# 用jmap查看Java进程的堆内存详情
jmap -histo <PID>
# 或者用jcmd
jcmd <PID> GC.heap_info
# 生成heap dump分析(注意:生产环境慎用,会暂停应用)
jmap -dump:format=b,file=/tmp/heap.hprof <PID>
# 用sar看历史趋势,确认是否是泄漏
sar -r 1 10
# 查看内存使用是否持续增长(对比不同时间的快照)
ps aux --sort=-%mem > /tmp/mem_before.txt
sleep 300
ps aux --sort=-%mem > /tmp/mem_after.txt
diff /tmp/mem_before.txt /tmp/mem_after.txt
我有一个真实案例:一台AlmaLinux 8的服务器跑了三个月后开始频繁卡顿。用free -h一看,available只剩200MB,swap用了16GB。用ps查了之后发现是一个Go写的后台服务,内存从最初的50MB涨到了4GB以上。用pprof分析了之后发现是一个map没有做大小限制,每次请求就往里面塞数据,永远不清理。修复方法是在map操作外面加一个LRU缓存,最大存10000条,超出就淘汰最老的。
防御措施
# 1. 设置合理的swappiness
# 默认值是60,对于SSD服务器可以适当降低减少swap使用
echo "vm.swappiness=10" > /etc/sysctl.d/99-swappiness.conf
sysctl -p /etc/sysctl.d/99-swappiness.conf
# 2. 限制进程的内存使用(通过systemd)
# 在service文件里添加
# [Service]
# MemoryMax=4G
# MemoryHigh=3G
# 3. 配置OOM score,保护关键进程
# PID越小的进程oom_score_adj越低,越不容易被杀
echo -1000 > /proc/1/oom_score_adj # systemd本身
echo -500 > /proc/$(pgrep sshd)/oom_score_adj # SSH
# 4. 设置告警
cat > /usr/local/bin/mem_alert.sh << 'EOF'
#!/bin/bash
AVAIL=$(free -m | awk 'NR==2{printf "%.2f", $7/$2 * 100.0}')
if (( $(echo "$AVAIL < 10" | bc -l) )); then
echo "Memory alert: ${AVAIL}% available on $(hostname)" | mail -s "Memory Alert" admin@example.com
fi
EOF
chmod +x /usr/local/bin/mem_alert.sh
网络断连——当SSH变成”连不上也杀不掉”
网络问题是最让人头疼的,因为你通常是通过网络来排查问题的。当SSH连不上的时候,你基本处于”盲排查”的状态。
第一层:确认问题范围
# 如果你还能登上去,先跑这些命令保留现场
# 查看网络接口状态
ip addr show
ip link show
# 查看路由表
ip route show
# 查看DNS配置
cat /etc/resolv.conf
# 查看网络连接状态
ss -tunap
# 查看防火墙规则
nft list ruleset
# 或者旧版
iptables -L -n -v
# 查看网络相关的systemd服务状态
systemctl status NetworkManager
systemctl status systemd-networkd
如果系统完全无法SSH连接,而你又没有IPMI/KVM访问权限,那就只能靠”盲操作”了。比如先判断是本地网络问题还是远程问题:
# 如果你能通过其他方式(比如VNC、云服务商的控制台)登录
# 先检查本地网络栈是否正常
ping 127.0.0.1 # 环回正常
ping <本机IP> # 本机网卡正常
ping <网关IP> # 到网关正常
ping 8.8.8.8 # 出公网正常
通过这一串ping,你可以判断网络问题出在哪一层。全部正常但SSH连不上,那就是SSH服务本身的问题;到网关就不通了,那是内网或路由问题;能ping通IP但ping不通域名,那是DNS问题。
常见网络故障场景
场景一:网卡配置错误导致断网
# 查看当前网卡配置
nmcli device show
nmcli connection show
# 查看最近的配置变更
journalctl -u NetworkManager --since "1 hour ago"
# 恢复默认网络配置(如果你有root权限)
# 对于RHEL系系统,网卡配置在/etc/sysconfig/network-scripts/
ls -la /etc/sysconfig/network-scripts/
# 如果配置文件被改坏了,从备份恢复
cp /etc/sysconfig/network-scripts/ifcfg-eth0.bak /etc/sysconfig/network-scripts/ifcfg-eth0
nmcli connection reload
nmcli connection up eth0
场景二:防火墙规则锁死了自己
这是新手最常踩的坑。改iptables或nftables规则的时候,不小心把SSH端口也挡了。
# 查看当前防火墙规则
nft list ruleset
iptables -L -n -v --line-numbers
# 如果确认是防火墙问题但已经连不上了
# 可以在控制台执行紧急恢复:
# 清除所有iptables规则(危险!仅在没有其他选择时)
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
# 或者用nftables
nft flush ruleset
场景三:IP冲突
两台机器用了同一个IP,网络时断时续,表现为SSH偶尔能连偶尔不行。
# 查看ARP表,确认是否有IP冲突
ip neigh show
arp -a
# 如果有重复的MAC地址对应同一个IP,那就是冲突了
# 用arp-scan扫描网段确认
arp-scan --localnet
场景四:DNS解析失败
# 测试DNS
dig example.com
nslookup example.com
getent hosts example.com
# 检查resolv.conf
cat /etc/resolv.conf
# 检查systemd-resolved服务
systemctl status systemd-resolved
resolvectl status
# 如果是DNS问题,可以临时修改
echo "nameserver 8.8.8.8" > /etc/resolv.conf
# 但更好的做法是修改NetworkManager配置
nmcli con mod <连接名> ipv4.dns "8.8.8.8,1.1.1.1"
nmcli con up <连接名>
场景五:端口被占用或服务没启动
# 检查SSH服务状态
systemctl status sshd
# 检查SSH监听端口
ss -tlnp | grep :22
# 查看SSH配置文件
cat /etc/ssh/sshd_config | grep -v "^#" | grep -v "^$"
# 测试SSH服务是否正常响应
ssh -v localhost # 本地测试,加-v看详细连接过程
网络问题的预防
# 1. 配置多个DNS服务器
nmcli con mod <连接名> ipv4.dns "8.8.8.8,1.1.1.1,223.5.5.5"
# 2. 设置防火墙规则的自动化测试(改规则前先备份)
nft list ruleset > /etc/nftables/ruleset.bak.$(date +%Y%m%d%H%M%S)
# 3. 使用fail2ban防止暴力破解导致SSH被堵
dnf install -y fail2ban
systemctl enable --now fail2ban
# 4. 配置告警:当网络接口down时通知
cat > /etc/NetworkManager/dispatcher.d/00-alert << 'EOF'
#!/bin/bash
if [ "$2" = "down" ]; then
echo "Network interface $1 went down on $(hostname)" | mail -s "Network Alert" admin@example.com
fi
EOF
chmod +x /etc/NetworkManager/dispatcher.d/00-alert
IO阻塞——比CPU和内存更难发现的”慢性杀手”
有时候系统不卡CPU也不卡内存,但就是响应极慢,命令执行卡住,SSH登录要等好几分钟。这种时候大概率是IO阻塞了。
定位IO问题
# 查看IO等待情况
iostat -x 1 5
# 查看哪个进程在吃IO
iotop -aoP
# 查看IO统计详情
cat /proc/diskstats
# 查看文件系统使用情况
df -h
du -sh /var/log /tmp /home/*
# 查看inode使用情况(有时候磁盘没满但inode用完了)
df -i
iostat的输出里重点关注这几个指标:
- %util:磁盘利用率,接近100%说明磁盘已经饱和
- await:IO平均等待时间,超过100ms就要警惕了
- r_await / w_await:读/写平均等待时间
常见IO问题原因
1. 日志写爆
# 查找大日志文件
find /var/log -size +100M -exec ls -lh {} \;
# 清理或轮转日志
journalctl --vacuum-size=100M # 只保留最近100M的journal日志
journalctl --vacuum-time=7d # 只保留7天的
2. 磁盘空间或inode耗尽
# 检查磁盘空间
df -h
# 检查inode
df -i
# 如果inode用完了,通常是大量小文件导致的
# 查找大量小文件的目录
find / -xdev -type f | cut -d'/' -f2,3,4 | sort | uniq -c | sort -rn | head -20
3. RAID卡或磁盘硬件故障
# 查看SMART信息(需要smartmontools)
smartctl -a /dev/sda
# 查看系统日志中的磁盘错误
dmesg | grep -iE 'error|fail|smart|ata|scsi'
journalctl -k | grep -iE 'error|fail|i/o'
# 查看RAID状态(如果有硬件RAID)
cat /proc/mdstat # 软RAID
# 或者用厂商工具查看硬件RAID状态
内核恐慌——最后的”求救信号”
Kernel Panic是Linux最严重的问题,系统会直接停止运行,屏幕上一片红字或白字。这种情况下,用户能做的有限,但记录信息对于后续排查至关重要。
如何获取panic信息
# 1. 确保kdump服务已启用(下次panic时能保存崩溃转储)
systemctl status kdump
# 如果没启用
systemctl enable --now kdump
# 2. 查看之前的panic记录
journalctl -k -b -1 # 上一个boot的kernel日志
dmesg -T | tail -100 # 最近的内核消息
# 3. 崩溃转储文件通常在
ls -la /var/crash/
ls -la /tmp/coredump*
# 4. 分析崩溃转储
# 需要crash工具
dnf install -y crash
crash /usr/lib/modules/$(uname -r)/vmlinux /var/crash/*/vmcore
常见panic原因
- 驱动bug:加载了有问题的内核模块,通常是第三方驱动
- 内存硬件故障:用memtester或memtest86+检测
- 文件系统损坏:EXT4/XFS文件系统出问题
- 内核bug:比较罕见,AlmaLinux的内核经过充分测试,但如果用了非标准内核版本(比如主线下发的内核),有可能遇到
当系统彻底死了——能做的事
如果以上所有方法都用过了,系统还是死机,那你可能需要做最后的挣扎:
# 1. 强制重启(这是最后的手段,数据可能丢失)
# 通过IPMI/控制台:
echo b > /proc/sysrq-trigger # 紧急重启(如果还能响应sysrq)
# 2. 如果完全无响应
# 通过IPMI的电源控制重启
# 或者去机房按物理重启键
# 3. 重启后检查系统健康状况
dmesg -T | tail -50 # 内核启动日志
journalctl -xb # 本次启动的完整日志
systemctl --failed # 启动失败的服务
fsck -n /dev/sda1 # 文件系统检查(只读,不修复)
重启之后第一件事是看日志,确认是什么原因导致宕机的。很多时候,重启能暂时解决问题,但根因不解决的话,问题还会再来。
一个真实的故事——从宕机到建立防御体系
去年我负责过一台AlmaLinux 9的Web服务器,运行的是一个Node.js应用加PostgreSQL数据库。这台服务器部署在云端,没有IPMI,只有SSH访问。
问题发生在一个周五的晚上。客户反馈网站打不开了,我登录SSH发现命令执行极慢,top跑了十秒钟才出来结果。我花了十分钟才看到top的输出——系统里有大约500个node进程,CPU占满了,内存也用了90%以上。
原来是一个自动化部署脚本出了bug,每次部署都会启动一个新的Node进程但不会杀掉旧的,加上应用本身没有做优雅重启,导致进程越来越多。到周五晚上已经有500多个node进程在跑,系统彻底撑不住了。
我当时的处理步骤:
# 1. 先杀掉多余的node进程,恢复系统基本可用
pkill -f 'node /app/server.js' # 只杀应用进程,不杀ssh
systemctl restart node-app # 重启服务
# 2. 检查部署脚本的bug
cat /opt/deploy.sh
# 3. 修复脚本,加上进程管理和幂等性
# 4. 配置systemd服务,限制内存和CPU
# 5. 加了监控告警,内存超过80%就通知
修复之后的systemd服务配置:
[Unit]
Description=Node.js Web Application
After=network.target postgresql.service
[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/opt/app
ExecStart=/usr/bin/node /opt/app/server.js
ExecReload=/bin/kill -HUP $MAINPID
# 资源限制
MemoryMax=2G
MemoryHigh=1.5G
CPUQuota=80%
Nice=10
# 崩溃重启策略
Restart=on-failure
RestartSec=10s
StartLimitBurst=5
StartLimitIntervalSec=300
# 安全加固
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
这个配置之后,即使部署脚本再出问题,也不会让系统彻底崩溃。系统最多就是服务重启几次,不会影响到其他服务。
写在最后
AlmaLinux是一个相当稳定的系统,绝大多数”宕机”问题都不是系统本身的问题,而是配置错误、资源耗尽或者软件bug导致的。遇到系统卡死的时候,记住这个排查思路:
- 先判断严重程度——是完全死机还是部分不响应
- 看日志——
journalctl和dmesg是最好的朋友 - 定位资源瓶颈——CPU、内存、IO、网络,通常只有一个
- 找到根因——不要只处理症状,要找出为什么会这样
- 建立防御——告警、限制、监控,让下次类似问题不再致命
系统运维就像给汽车做保养,预防永远比抢修更重要。一个健康的AlmaLinux系统,应该是有监控、有告警、有备份、有文档的,而不是等到出了事才手忙脚乱。希望这篇文章能帮你在系统”发疯”的时候多一份从容。
