结论: 服务器宕机(Server Downtime)的处置顺序是"先恢复、后定位、再复盘"——先用重启/切流量/回滚把业务拉起,再按硬件、系统、网络、应用、数据库、人为、外部依赖七类逐一排查根因,最后用 MTTR 与复盘模板固化改进项。90% 的宕机可在 15 分钟内通过日志、监控曲线与变更记录三条线索定位。
引言:为什么宕机排查必须有一套固定方法论
服务器宕机是所有运维场景里压力最大的一种:业务停摆、用户投诉、老板催问,而现场往往一片混乱——有人说是网络问题,有人说是数据库崩了,还有人怀疑被攻击。没有方法论的团队会陷入"重启试试、改配置试试"的随机试错,把 MTTR(Mean Time To Repair,平均修复时间)从 15 分钟拖到 2 小时。
宕机排查的核心难点不在于"技术有多难",而在于信息不全时的决策顺序。真正成熟的处置流程一定是:先止血(恢复服务),再取证(保存现场),后定位(找根因),最后复盘(防复发)。本文按这个顺序给出一套可落地的完整方案:原因分类表、时间线排查法、可用性计算、复盘模板与预防措施。文中的命令以 CentOS 7 / Rocky Linux 9 / Ubuntu 24.04 LTS 为例,截至 2026 年主流发行版均已默认使用 systemd 与 journald。
一、服务器宕机原因分类:一张表看清七大类
服务器宕机不是一个单一故障,而是一类现象。定位的第一步是把现象归入正确的类别,因为不同类别的排查路径完全不同。下表按发生频率从高到低排列,并给出每类的典型特征与首要排查动作。
| 类别 | 典型原因 | 识别特征 | 首要排查动作 |
|---|---|---|---|
| 硬件 | 内存 ECC 报错、磁盘坏道、电源故障、RAID 卡掉盘 | 直接断电/重启,无系统日志;IPMI/iDRAC 有告警 | 查带外管理口(IPMI/iDRAC/iLO)硬件日志 |
| 系统 | 内核 panic、OOM Killer 杀进程、文件系统只读、inode 耗尽 | 有 kernel panic、Out of memory、Read-only file system 日志 | 查 journalctl -k 与 dmesg |
| 网络 | 机房链路中断、BGP 抖动、交换机故障、网卡 down、DNS 污染 | 本机正常但外部 ping 不通;部分地域不通 | mtr、ethtool、多地域拨测 |
| 应用 | 进程崩溃、端口消失、死锁、线程池耗尽、内存泄漏 | 端口无监听,进程不存在或假死 | ss -lntp、systemctl status、jstack |
| 数据库 | 连接数打满、慢 SQL、主从延迟、磁盘满导致写入失败 | 应用报 Too many connections、Lock wait timeout | 查 SHOW PROCESSLIST、慢日志 |
| 人为 | 误删文件、误执行 rm -rf、错误配置发布、错误防火墙规则 | 时间上与某次操作高度重合 | 查 history、审计日志、发布记录 |
| 外部依赖 | 第三方 API 超时、CDN 故障、证书过期、云厂商故障 | 本机一切正常,但依赖方返回错误 | 查依赖方状态页、curl 直连测试 |
判断归属的最快方法是"三问":
- 服务端口还在吗? 不在 → 应用/系统类;在 → 进入下一问。
- 本机 curl 能通吗? 本机通、外网不通 → 网络类;本机也不通 → 应用类。
- 最近 30 分钟有变更吗? 有 → 优先怀疑人为/发布类。
二、宕机后的黄金 5 分钟:标准处置时间线
宕机处置的价值随时间急剧衰减。建议团队把前 5 分钟的动作固化成清单,避免临场慌乱。
0~1 分钟:确认与止血
目标是"确认影响面 + 决定是否需要立即恢复动作"。
# 1. 确认主机是否存活(从另一台机器发起)
ping -c 4 10.0.0.11
# 2. 确认业务端口
nc -zv -w 3 10.0.0.11 80
curl -sv -m 5 http://10.0.0.11/healthz
# 3. 确认 SSH 是否可登(可登 = 系统还在,多半是应用层问题)
ssh -o ConnectTimeout=5 ops@10.0.0.11 'uptime; ss -lntp | head -20'- SSH 能登、端口没了 → 应用层故障,优先重启服务进程。
- SSH 能登、负载飙高 → 资源类故障,查 CPU/内存/磁盘 IO。
- SSH 登不上、ping 也不通 → 系统或硬件层故障,走带外管理(IPMI/iDRAC)或云控制台。
1~3 分钟:取证(这一条最容易被忽略)
在重启之前先保存现场,否则根因会永久丢失。这一步决定了你事后能不能写出复盘报告。
# 保存内核与系统日志(关键!reboot 后 journald 非持久化内容会丢)
journalctl -k -b -1 > /tmp/kernel_prev.log 2>/dev/null # 上一次启动的内核日志
journalctl -b -1 --since "2 hours ago" > /tmp/sys_prev.log 2>/dev/null
dmesg -T > /tmp/dmesg.log
# 保存资源快照
ps aux --sort=-%mem | head -30 > /tmp/ps_top.log
free -m > /tmp/mem.log; df -h > /tmp/disk.log; df -i >> /tmp/disk.log
ss -s > /tmp/ss.log; ss -lntp > /tmp/ports.log
# 保存 OOM / panic 痕迹
grep -iE "oom|killed process|panic|call trace" /var/log/messages /tmp/kernel_prev.log 2>/dev/null注意:多数发行版默认 /var/log/journal 不存在,journald 只把日志写在内存 /run/log/journal,重启即丢。取证前务必先执行持久化:
mkdir -p /var/log/journal && systemd-tmpfiles --create --prefix /var/log/journal
systemctl restart systemd-journald3~5 分钟:恢复动作的选择
恢复动作按"破坏性从小到大"排序,优先选代价最小的:
- 重启应用进程(
systemctl restart nginx)—— 不改变系统状态。 - 回滚最近一次发布/配置 —— 针对明确由变更引发的故障。
- 切流量到备用节点 —— 有高可用架构时的首选。
- 重启整机(
systemctl reboot)—— 保留现场后执行。 - 强制断电重启(云控制台"强制重启")—— 针对内核 hang 死、SSH 无响应。
只有在业务可用性优先于根因分析时才重启。 对反复出现的宕机,必须留一次机会做完整取证。
三、MTTR 与可用性:把宕机量化成可管理的指标
宕机无法完全消灭,但可以量化管理。三个必须掌握的指标:
- MTBF(Mean Time Between Failures,平均无故障时间):两次故障之间的平均运行时间。
- MTTR(Mean Time To Repair,平均修复时间):从故障发生到服务恢复的平均耗时,包含发现、定位、修复、验证四段。
- 可用性(Availability) = MTBF / (MTBF + MTTR) × 100%。
常用"几个 9"对应的年度/月度停机时长:
| 可用性等级 | 年停机上限 | 月停机上限 | 适用场景 |
|---|---|---|---|
| 99%(两个 9) | 87.6 小时 | 7.3 小时 | 内部系统、测试环境 |
| 99.9%(三个 9) | 8.76 小时 | 43.8 分钟 | 绝大多数企业官网、业务系统 |
| 99.99%(四个 9) | 52.6 分钟 | 4.38 分钟 | 电商核心链路、支付 |
| 99.999%(五个 9) | 5.26 分钟 | 26.3 秒 | 金融、电信级核心 |
计算示例:某系统一年宕机 3 次,总停机 50 分钟,则年可用性 = (525600 - 50) / 525600 = 99.9905%,达到四个 9。若同样 3 次但每次耗时 40 分钟(总 120 分钟),可用性降为 99.977%,即三个 9 都不到——降 MTTR 比降故障次数更容易见效,这就是为什么自动化恢复和一键回滚值得投入。
MTTR 的四段拆解是改进的关键:
| 阶段 | 含义 | 压缩手段 |
|---|---|---|
| MTTD(发现) | 故障发生到告警触达 | 监控覆盖率、拨测、告警直达手机 |
| MTTA(确认) | 告警到人确认 | 值班制度、告警降噪 |
| MTTRepair(修复) | 定位到执行恢复 | 预案、一键脚本、自动化切流 |
| MTTV(验证) | 恢复到确认业务正常 | 健康检查、自动化验证 |
四、根因定位:按类别给出命令与判断依据
4.1 系统层:OOM 与内核 panic
内存耗尽触发 OOM Killer 是中小企业服务器最常见的"离奇重启/进程消失"原因。
# 查看是否被 OOM 杀过(CentOS/RHEL 系在 messages,Ubuntu 在 syslog/kern.log)
grep -iE "out of memory|killed process|oom-kill" /var/log/messages /var/log/syslog 2>/dev/null | tail -20
# journald 方式(推荐)
journalctl -k --since "1 hour ago" | grep -iE "oom|killed process"
journalctl -u nginx --since "1 hour ago" | tail -50
# 查看上次是否异常关机
last -x | head -20 # 看 reboot/shutdown 记录,正常 reboot 会有对应 shutdown 行
journalctl --list-boots # 列出历次启动,异常启动之间时间间隔突兀即为宕机判断要点:last -x 中如果出现 reboot 行但前面没有配对的 shutdown 行,说明是非正常断电或硬重启;journalctl --list-boots 中出现意外的启动序号,对应时间点即为宕机时刻。
4.2 磁盘:空间与 inode 双杀
df -h # 空间
df -i # inode(小文件爆多时空间没满但 inode 满)
du -xh --max-depth=1 / 2>/dev/null | sort -rh | head -15 # 定位大目录
lsof +L1 # 已删除但仍被进程占用的文件(空间不释放的元凶)lsof +L1 列出的 deleted 文件若被 nginx/java 占着,直接 truncate -s 0 /proc/ 可在线释放,无需重启进程。
4.3 应用层:端口、进程与假死
ss -lntp | grep -E ":80|:443|:8080" # 端口是否还在监听
systemctl status nginx --no-pager -l # 服务状态与最后几行日志
curl -sv -m 5 http://127.0.0.1/healthz # 本机自测,区分"服务挂"和"网络不通""假死"的典型特征:端口在监听、进程在,但请求无响应或超时。常见原因是线程池/连接池耗尽、死锁、后端依赖阻塞。此时需要抓栈:Java 用 jstack -l (间隔 5 秒抓 3 次对比),Node.js 用 --inspect,PHP-FPM 查 pm.max_children 是否被打满。
4.4 网络层:分层排除
ip a; ip r # 本机地址与路由
ethtool eth0 | grep -E "Link detected|Speed" # 网卡物理层
mtr -rw -c 50 8.8.8.8 # 沿途丢包定位(比 traceroute 更准)
ss -s # 连接数统计,判断是否被打满
cat /proc/net/sockstat # 套接字状态4.5 变更关联:最容易被忽略的一条线索
# 谁在什么时候执行过什么
grep -iE "sudo|su |rm -rf|systemctl (stop|restart)" /var/log/secure 2>/dev/null | tail -40
cat /var/log/audit/audit.log 2>/dev/null | tail -20
# 最近变更的配置文件
find /etc -maxdepth 3 -type f -mmin -120 2>/dev/null | head -20经验值:约 60%~70% 的线上故障与变更相关(发布、配置修改、参数调整)。排查时优先对齐"故障起始时间 vs 变更时间",往往能瞬间缩小范围。
五、复盘模板:把一次宕机变成一份资产
没有复盘的宕机等于白宕。建议统一使用以下模板(可直接复制进 Wiki):
## 故障复盘:<一句话标题>
- 故障等级:P0/P1/P2
- 影响时间:2026-03-12 14:23 ~ 14:58(共 35 分钟)
- 影响范围:订单下单接口 100% 失败,影响用户约 1.2 万
### 时间线(Timeline)
| 时间 | 事件 | 处理人 |
|---|---|---|
| 14:23 | 监控告警:5xx 比例 > 30% | 监控 |
| 14:26 | 值班响应,确认网关 502 | 张三 |
| 14:31 | 定位:应用节点 2 台 OOM 重启 | 张三 |
| 14:40 | 临时扩容内存 8G→16G 并重启 | 李四 |
| 14:58 | 业务恢复,核心接口成功率 99.98% | 李四 |
### 根因(Root Cause)
(写清楚直接原因 + 深层原因,避免只写"内存不足")
直接原因:促销流量超预期 3 倍,JVM 堆上限 4G 被打满。
深层原因:压测未覆盖大促场景;堆内存告警阈值设置在 95%,缓冲不足。
### 为什么没早发现(Detection Gap)
- 缺少 JVM 堆使用率的趋势告警,只有瞬时阈值。
### 改进项(Action Items)
| 改进项 | 类型 | 负责人 | 截止 | 状态 |
|---|---|---|---|---|
| JVM 堆告警改为 80% 且持续 5 分钟 | 检测 | 李四 | 03-20 | 待办 |
| 大促前全链路压测纳入发布流程 | 预防 | 王五 | 03-31 | 待办 |
### 经验沉淀
- 有效动作:先切流量再修,避免影响面扩大。
- 无效动作:反复重启进程,浪费 8 分钟。复盘的三条铁律:对事不对人(不追责个人,追流程漏洞)、改进项必须有负责人和截止日期、区分"直接原因"与"深层原因"——只写前者会导致同类故障反复发生。
六、预防措施:让宕机从"救火"变成"可控"
预防分四层,投入产出比从上到下递减:
- 检测层(性价比最高):全端口与全接口的拨测 + 资源趋势告警(CPU 80% 持续 5 分钟、磁盘 85%、内存 90%)。告警必须能直达手机,且有升级机制(15 分钟未响应升级到经理)。
- 冗余层:至少 2 个应用节点 + 负载均衡(Load Balancing);数据库主从;避免单点。
- 自动恢复层:进程守护(
systemd的Restart=always)、健康检查自动摘除异常节点、OOM 后自动拉起。 - 变更管控层:变更窗口、灰度发布、一键回滚、配置版本化。
# /etc/systemd/system/myapp.service —— 用 systemd 实现进程崩溃自动拉起
[Unit]
Description=My Application
After=network.target
[Service]
Type=simple
ExecStart=/opt/myapp/bin/myapp --config /etc/myapp/config.yaml
Restart=always
RestartSec=5
StartLimitIntervalSec=300
StartLimitBurst=5
MemoryMax=4G # 内存上限,超限触发 systemd OOM 而非整机 OOM
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.targetMemoryMax=4G 这一项很关键:它把进程级内存限制交给 systemd(cgroup),避免单个应用吃光整机内存导致 OOM Killer 误杀其他关键进程(如 sshd、数据库)。
企业QQ咨询




