服务器不稳定排查指南:从CPU、内存到网络的系统化定位方法

服务器不稳定排查指南:从CPU、内存到网络的系统化定位方法 我经常在线上问题群里看到这样的描述“服务器没有挂但接口时不时超时重启一下又好一阵子过几天又开始了。”这种问题往往最让人头痛因为它既不像宕机那样定位明确也不像代码报错那样有堆栈可以查。它表现出来的是“时好时坏”是“偶发超时”是“重启后短暂恢复”而这种状态就是本文要讨论的“不稳定服务器”。本文是《不稳定服务器的统治》系列第二季。第一季我们重点解决“怎么从零了解一台服务器”这一季的目标更直接遇到一台不稳定的服务器如何按照一套可复用的路径去排查而不是靠猜和反复重启。内容会覆盖 CPU、内存、磁盘、网络四个核心维度的排查方法也会补充虚拟化环境、云服务器、容器场景下常见的特殊坑点。如果你是后端开发、运维工程师、SRE或者正在自己折腾什么技术项目这篇文章都值得跟着过一遍。读完你至少能回答三个问题服务器负载到底看哪个指标内存被打满之前系统日志里会留下什么为什么网络明明通接口还是超时把这些问题的边界理清不稳定服务器的统治就会被拉下马。1. 服务器不稳定到底在说什么1.1 不稳定不是彻底宕机而是“时好时坏”先给“不稳定服务器”下一个实用定义一台服务器如果偶尔宕机、频繁重启那是高可用问题如果从某一刻开始持续性能下降那是容量或性能瓶颈而“不稳定”通常是间歇性异常比如每过几十分钟出现一次超时或者每天固定时段 CPU 飙升又或者内存占用只涨不降直到被杀进程后才恢复。这种“时好时坏”的状态比彻底宕机更难处理原因在于它的复现窗口很随机。你登录服务器时可能一切正常load average 很漂亮内存也没满可业务方就是持续反馈“又卡了”。于是很多人陷入一个循环出了问题先重启重启后暂时恢复恢复后没有进一步排查直到下次再犯。这样下去不稳定会变成常态而且每次重启都会抹掉部分现场证据后续根因分析更难做。1.2 不稳定服务器的典型表现从运维和开发的实际经验看不稳定服务器的典型表现可以归纳为以下几类平均负载忽高忽低CPU 使用率有时冲到接近 100%有时又很低。内存持续增长最终触发 OOMOut Of Memory机制进程被系统杀掉。磁盘接近写满或者磁盘 IO 等待时间明显偏高。网络偶发丢包、TCP 重传增多客户端频繁报连接超时。应用进程本身没有退出但对外端口不可连接或响应极慢。服务器时间出现偏移导致日志时间线错乱、定时任务执行异常。容器或虚拟机场景下宿主机资源竞争导致指标异常。这些表现往往不是独立的。比如磁盘 IO 被打满之后业务线程全部卡在等待 IO从外部看就是接口超时内存被 OOM killer 干掉后进程可能自动重启从外部看就是“服务闪断了一下”。所以排查不稳定服务器时不能只看一个指标需要按照固定顺序把所有关键指标过一遍。1.3 为什么服务器不稳定很难排查难排查主要有三个原因。第一很多服务器在上线初期没有配置监控等到出问题时现场已经被下一次重启或日志滚动覆盖。第二排查手段不系统很多人习惯登录服务器后先看 top但 top 只能看到当下的瞬时状态看不到几分钟前的峰值。第三多个指标同时异常时很难分辨因果。比如 CPU 高可能是某个业务进程导致也可能是磁盘 IO 慢导致大量 D 状态进程堆积。解决这个问题的关键是建立一套固定的排查顺序并且理解每个指标之间的关联。下面我们从排查前的准备开始一步一步把链路打通。2. 排查前必须准备的三件事2.1 监控先行没有指标就没有排查排查不稳定服务器最忌讳的就是等事情发生后再登录服务器。如果事前有监控数据至少能回答几个关键问题问题从什么时间开始哪个指标先异常持续了多久反之如果没有任何历史指标排查基本就是大海捞针。基础监控至少包括系统负载、CPU、内存、磁盘、网络、关键进程状态和系统日志。生产环境推荐使用 Prometheus 加 node_exporter 加 Grafana 的组合也可以使用云厂商自带的监控平台。对于个人测试机或临时排查可以先准备一个手动巡检脚本快速收集现场信息。#!/bin/bash # 文件路径/usr/local/bin/server_check.sh # 服务器稳定性快速巡检脚本建议配合 cron 每 5 分钟执行一次 echo $(date %Y-%m-%d %H:%M:%S) 开始巡检 echo --- 负载与进程状态 --- uptime top -b -n 1 | head -20 echo --- 内存状态 --- free -h echo --- 磁盘容量 --- df -h echo --- 磁盘 inode --- df -i echo --- 系统日志中的 OOM / IO 错误 --- dmesg -T 2/dev/null | grep -iE oom|killed process|blocked for more than | tail -20 echo --- 正在监听的端口 --- ss -tlnp echo --- TCP 重传统计 --- netstat -s | grep -i segments retransmited\|retransmited || true这个脚本里的每条命令都有明确作用。uptime看平均负载top看进程和 CPU 状态free -h看内存df -h和df -i分别看磁盘容量和 inodedmesg翻系统日志里的 OOM 和 IO 阻塞记录ss -tlnp看当前监听的端口netstat -s看 TCP 重传。出现不稳定时先跑一遍很多问题都能直接暴露。2.2 时间同步所有日志的时间线必须一致排查不稳定服务器时有一件很容易被忽略但极其重要的事时间同步。应用日志、系统日志、监控数据分布在多台服务器上如果各自时间不一致串时间线时会非常痛苦。常见的表现是数据库日志显示某条 SQL 在 10:00:00 执行应用日志却显示 10:03:00 才发起请求中间这 3 分钟是时间差还是性能问题根本说不清。Linux 服务器推荐使用 chrony 替代传统 NTP 服务。配置文件位于/etc/chrony/chrony.conf最小配置如下# /etc/chrony/chrony.conf 示例server 地址请根据你的网络环境调整 server ntp.aliyun.com iburst server ntp.tencent.com iburst # 允许本地客户端同步自己的时间 local stratum 10 # 启动并设置开机自启 systemctl enable chronyd systemctl restart chronyd # 查看时间同步状态 chronyc sources -v chronyc tracking如果你需要检查校时服务器NTP 服务器的 123 端口是否被防火墙关闭可以尝试用nc -uvz NTP服务器IP 123测试 UDP 端口连通性但 UDP 探测的结果不如 TCP 直观更可靠的方式是直接在客户端执行chronyc sources -v看^*标记是否出现。*表示当前已同步源^表示该源可用。如果一直看不到同步源再去检查防火墙和网络路由。还要注意时区问题。如果服务器时区不对即使时间同步成功业务看到的日志时间也可能和预期不一致。可以用timedatectl set-timezone Asia/Shanghai设置时区用timedatectl查看当前系统时间和时区信息。2.3 建立变更记录90% 的不稳定来自变更监控和时间同步都是“事后取证”的基础但真正能大幅缩小排查范围的是变更记录。很多人排查到深夜最后发现是昨天加了一个定时任务或者升级了某个依赖包。可如果没有变更记录所有可能性都只能靠猜。这里说的变更不仅指代码发布还包括系统内核参数调整、数据库配置修改、中间件版本升级、定时任务新增、防火墙规则变更、云资源规格调整等。建议哪怕是个人服务器也用一个简单的 Markdown 文件记录每次变更的时间和内容。团队环境则应该借助发布平台或 CI/CD 系统的历史记录保留每个环境的完整变更历史。这样当服务器开始不稳定时第一步就可以对比“不稳定开始时间”和“最近变更时间”如果高度重合优先回滚或排查变更项效率会高很多。3. 第一层排查CPU 与平均负载3.1 先看平均负载而不是直接看 CPU 使用率很多人习惯用top里的%Cpu判断服务器是否吃紧但平均负载load average是更值得先看的指标。平均负载代表单位时间内正在运行和不可中断的进程数量它不只反映 CPU 使用还包含处于 D 状态不可中断睡眠的进程。一个典型的场景是磁盘 IO 出问题后大量进程阻塞在 IO 等待上平均负载飙升但 CPU 使用率并不高。执行uptime可以看到三组负载值分别对应过去 1 分钟、5 分钟和 15 分钟的平均值。如果 1 分钟负载远高于 15 分钟负载说明问题刚刚发生如果三者都很高说明问题已经持续一段时间。判断负载是否过高不能只看绝对值要结合 CPU 核心数。经验上当平均负载持续超过核心数的 70% 到 80% 时就需要开始排查了。比如 4 核服务器负载持续高于 3 就要警惕。3.2 定位消耗 CPU 的进程确认负载过高后下一步是找出到底是谁在消耗资源。top -c可以在进程列表里显示完整命令行按大写P可以按照 CPU 使用率排序。为了看到更细粒度的数据可以配合以下命令# 按 CPU 列出前 20 个进程 ps -eo pid,ppid,user,%cpu,%mem,cmd --sort-%cpu | head -20 # 观察指定进程的 CPU 变化 pidstat -p PID 1 5如果消耗 CPU 的是业务进程需要进一步看是正常的流量增长还是代码死循环。如果是 Java 应用可以使用top -Hp PID查看线程级 CPU 消耗再用jstack导出线程栈来确定具体代码位置。如果是数据库常见原因是缺少索引或 SQL 没有命中缓存。如果是突然多出来的陌生进程则要立刻警惕安全问题检查是否被入侵或者被恶意程序利用。3.3 僵尸进程与不可中断进程进程状态也很关键。ps -eo stat,pid,ppid,cmd | awk $1 ~ /D|Z/可以筛选出 D 状态和 Z 状态的进程。D 状态是不可中断睡眠通常代表进程正在等待内核 IO 完成大量 D 状态进程说明磁盘或网络 IO 存在严重阻塞。Z 状态是僵尸进程代表子进程已结束但父进程没有调用 wait 回收僵尸进程本身不占太多 CPU 和内存但会占用 PID大量累积会导致新进程无法创建。遇到大量 D 状态进程优先排查磁盘遇到大量僵尸进程优先排查父进程是什么为什么没有正确回收子进程。对于使用 gunicorn、Supervisor 等进程管理工具的场景还要确认进程管理器的配置是否正常避免僵死子进程持续堆积。4. 第二层排查内存4.1 free 输出里最容易误解的两个指标内存排查中有一个高频误区看到free -h里 used 很高就认为内存不足。实际上 Linux 会尽量利用空闲内存做缓存cached/buffers这部分内存在业务需要时可以释放。真正应该关注的是 available 字段它表示在不触发交换的情况下可供新进程使用的内存估计值。运行free -h时重点看 available 是否持续降低。如果 available 长时间接近 0同时 swap 使用率上升说明物理内存已经紧张系统开始使用交换分区。磁盘交换会带来极大的性能抖动从外部看就是服务时快时慢非常符合“不稳定服务器”的特征。4.2 OOM 发生时系统的“遗言”在哪里当内存真正耗尽时Linux 内核的 OOM killer 会选中一个进程并杀掉它以释放内存。被杀的进程不一定是内存占用最高的那个具体的得分逻辑还涉及进程优先级、运行时长等因素所以会有人遇到“明明另一个进程更占内存却把 Java 服务杀了”的情况。OOM 的痕迹不会出现在应用日志里而会出现在内核日志中。排查命令如下# 查看最近的 OOM 记录 dmesg -T | grep -iE out of memory|killed process # 使用 journalctl 查看内核日志 journalctl -k --since 2 hours ago | grep -iE oom|killed process如果应用进程经常“意外消失”登录服务器后第一件事就应该是执行这两条命令。看到Killed process 12345 (java)这样的记录说明不是应用自身崩溃而是操作系统主动杀掉了进程。根因通常不是“这次被杀”而是内存为什么持续增长。4.3 内存泄漏的初步定位思路内存排查不能只停留在“内存不够就扩容”很多情况下是程序存在内存泄漏。常见特征内存使用随运行时间缓慢上涨重启服务后明显回落运行几天后又接近峰值。定位时先看哪个进程内存最大# 按物理内存占用列出前 10 个进程 ps -eo pid,ppid,user,rss,cmd --sort-rss | head -10如果是 Java 应用可以用jmap -heap PID查看堆内存概况也可以借助 Arthas、JProfiler 等工具分析堆转储文件。Python 应用可以结合 tracemalloc 或 objgraph 定位对象引用问题。如果是容器环境别忘了看 cgroup 层面的限制容器内即使 free 显示正常也可能因为容器内存限制被 OOM 杀掉这时的证据可能在dmesg中显示为Memory cgroup out of memory。5. 第三层排查磁盘5.1 不只是容量还有 inode服务器磁盘问题最容易理解但也有一些隐蔽的坑。第一层是容量df -h可以直观看到每个分区使用比例当使用率达到 80% 以上时就要警惕。第二层是 inode也就是文件系统索引节点数量。如果创建了海量小文件比如临时文件、缓存文件、消息队列积压文件磁盘容量可能还没满inode 就已经耗尽此时创建任何文件都会提示No space left on device。用df -i可以查看 inode 使用率。如果 inode 使用率接近 100%要立刻找出小文件最多的目录。可以通过下面脚本快速定位# 统计 /var 下各目录文件数量 for dir in /var /tmp /home /opt; do echo $dir: $(find $dir -type f 2/dev/null | wc -l) done # 查看某个目录的 inode 消耗排行 du --inodes -x /var 2/dev/null | sort -k1 -n | tail -20注意找到积压目录后不要贸然批量删除。一定要先确认这些文件属于哪个应用是否还在被进程写。最安全的做法是先停止相关应用或确认文件无用再做清理清理前备份或至少将目录改名保留一段时间。5.2 IO 延迟高和磁盘阵列异常磁盘容量只是表面真正影响稳定性的是 IO 延迟。使用iostat -x 1可以观察每秒的 IO 情况重点关注%util和await。%util接近 100% 说明磁盘长期处于繁忙状态await是 IO 请求的平均等待时间数值越高代表响应越慢。还有一种情况容易被忽略磁盘阵列RAID中的一块硬盘故障导致阵列进入降级状态。此时系统还能正常工作但读写性能大幅下降而且数据冗余度已经降低存在数据丢失风险。对于硬件 RAID建议定时查看阵列管理工具的状态对于软件 RAID可以使用以下命令查看# 查看软 RAID 状态 cat /proc/mdstat如果阵列状态中出现degraded、removed或[U_]之类的标记说明有成员盘异常需要尽快备份数据并更换故障盘。对于生产环境磁盘阵列状态应该纳入日常监控和告警范围。5.3 日志无限增长导致磁盘占满日志是排查问题的重要依据但日志本身也会成为“罪魁祸首”。很多服务器不稳定就是/var/log目录被无限制增长的应用日志或容器日志塞满最终导致磁盘爆掉服务不断报错。常见做法是配置 logrotate 对系统日志和应用日志做轮转。容器化环境则要限制 Docker 日志的大小在/etc/docker/daemon.json中做如下配置{ log-driver: json-file, log-opts: { max-size: 100m, max-file: 3 } }这个配置表示单个容器日志文件最大 100MB最多保留 3 个文件。配置修改后需要重启 Docker 守护进程才能生效生产环境操作前要评估影响。除了日志临时目录、上传目录、备份文件也是磁盘增长的常见来源巡检时需要一并检查。5.4 共用磁盘的应用互相影响如果一个磁盘被多个应用共用那么某个应用的突增写入会拖慢其他应用。比如数据库和 Web 应用放在同一块云盘上当某条大 SQL 全表扫描导致磁盘 IO 飙高时Web 应用读取静态文件同样会受影响外部表现为接口变慢。如果条件允许建议把日志目录、数据库数据目录、应用临时目录拆分到不同磁盘从而隔离性能影响。6. 第四层排查网络6.1 网络问题先分层再定位网络不稳定的表现很复杂但排查时可以把问题拆成三层链路通不通、端口通不通、服务进程响应是否正常。直接从现象出发先跑几条基础命令# 测试到目标服务器的网络连通性 ping -c 5 服务器IP # 测试某个端口是否开放 telnet 服务器IP 端口 # 查看本地监听的端口 ss -tlnp # 看一个接口的完整响应时间 curl -w 总耗时: %{time_total}\n 连接耗时: %{time_connect}\n -o /dev/null http://127.0.0.1:8080/如果 telnet 能通但业务接口还是超时问题大概率在服务进程本身或应用层依赖。如果 ping 不通问题在链路或防火墙如果 ping 通、telnet 不通则要检查端口是否监听、防火墙规则是否允许访问。把问题限制在某个层面后排查范围会小很多。6.2 SSH 连接不稳定如何排查“连接远程服务器总是断”“VSCode 连接 SSH 远程开发一会儿就掉线”是非常典型的不稳定表现。SSH 连接不稳定通常有以下几个原因网络链路本身有丢包可以使用ping -c 100 IP | grep loss看丢包率。服务器负载过高或 IO 阻塞SSH 服务无法及时响应。sshd 并发连接配置太低导致新连接被拒绝。服务器开启了 DNS 反查但内网 DNS 解析很慢。客户端网络环境切换频繁连接存活时间太短。针对 sshd 配置可以在/etc/ssh/sshd_config中做以下优化# /etc/ssh/sshd_config 片段 UseDNS no GSSAPIAuthentication no # 提高并发连接与保持能力 MaxSessions 50 MaxStartups 30:50:100 ClientAliveInterval 60 ClientAliveCountMax 3UseDNS no可以避免 SSH 登录时做反向 DNS 解析ClientAliveInterval可以让服务端定期发送保活包减少因网络空闲导致的断连。修改配置后先用sshd -t检查语法再执行systemctl reload sshd平滑生效。客户端排查时可以使用ssh -vvv userhost观察连接卡在哪一步如果是公钥认证阶段卡住还要检查本地私钥和服务器authorized_keys的权限设置。6.3 TCP 重传与连接堆积网络不稳定还经常表现为 TCP 重传率升高。TCP 协议通过确认机制保证可靠传输如果数据包在链路中丢失或延迟发送方会重传。大量重传意味着链路质量差、带宽打满或中间设备出现丢包。查看重传和连接状态可以使用以下命令# 查看 TCP 重传统计 netstat -s | grep -i retransmited # 查看当前连接状态汇总 ss -s # 查看已建立连接数量 ss -tan state established | wc -l # 查看网卡丢包和错误统计 ethtool -S eth0 | grep -iE drop|err如果 established 连接数持续上涨应用日志却没有明显报错可能是连接池配置过大或者有大量慢请求占着连接不放。此时可以结合ss -tan看连接对端 IP 分布判断是否有异常访问或爬虫流量。生产环境建议对单 IP 并发连接数做限制同时优化应用的连接池和超时时间。6.4 DNS 与时间同步也会制造“假不稳定”还有一种容易被误认为服务器不稳定的是 DNS 解析问题。接口调用依赖外部服务时如果 DNS 解析经常超时业务表现为偶发超时。排查时执行time nslookup 域名如果解析耗时忽高忽低说明当前 DNS 服务器不稳定可以更换为内网稳定的 DNS 或开启本地 DNS 缓存。时间同步问题同样会表现出“不稳定”特征。比如定时任务在错误时间点启动导致业务高峰被额外任务抢占资源或者应用生成的 token 依赖时间戳时间跳变后出现大量验签失败。前面讲的 chrony 配置就是为此准备的。7. 虚拟化与云服务器场景7.1 云服务器的“邻居干扰”云服务器和物理服务器最大的区别在于你使用的是宿主机上划分出来的虚拟资源。如果宿主机上的其他实例业内常说的“邻居”突发占用大量 CPU、磁盘 IO 或网络带宽你的实例就会受到干扰。这种问题在共享型实例、免费云服务器或低配轻量应用服务器上更明显。判断是否被“邻居干扰”可以看 CPU 的 steal 指标。在top输出中%st代表当前 CPU 被宿主机强制偷走的时间比例。如果%st长时间较高说明宿主机资源竞争很激烈。云服务器场景下如果业务逻辑没有明显变化但性能突然波动优先对比监控里的%st和带宽流量。如果确认邻居干扰严重唯一有效的办法是迁移实例或升级到独享型规格单纯重启解决不了问题。7.2 突发 CPU 与带宽基线不少云服务器是突发型实例正常情况下允许短时间跑满 CPU但如果持续满负荷运行会被限流到基准性能附近。这会带来一种很有迷惑性的现象刚买来或刚重装系统时性能很好跑一段时间后突然变慢重启后又恢复。原因就是重启后 CPU 积分或突发额度被重新计算。面对这种情况不要盲目在系统层反复调参应该先到云控制台查看实例规格、CPU 突发额度和带宽基线。如果业务需要长期稳定运行应该选择性能型实例或者对任务进行削峰填谷避免长时间满跑。7.3 虚拟机、容器与裸金属的排查层级差异不同虚拟化技术下你能看到的系统指标含义并不相同。物理机或裸金属上free、top、iostat看到的都是真实硬件资源。KVM 虚拟机里部分指标是宿主机虚拟出来的CPU 型号和核数通常与实际一致但性能仍受宿主机调度影响。Docker 容器内执行top和free看到的是宿主机的内核视角不一定反映容器真实使用量更准确的应该使用docker stats查看容器资源占用。如果容器应用表现为不稳定优先检查容器是否接近 cgroup 限制例如内存达到 limit 后会被频繁 OOMCPU 达到 quota 后会被 throttle。宿主机上的其他容器也可能抢占资源。排查容器问题时需要同时查看宿主机指标和容器指标不能只看其中一层。8. 常见不稳定根因与修复对照表问题现象常见根因快速确认命令处理思路接口偶发超时CPU 不高宿主机 CPU steal 高或磁盘 IO 阻塞uptime/top 看%stiostat 看%util迁移实例拆分磁盘排查热点进程内存持续上涨后进程被杀应用内存泄漏或容器内存限制过小dmesg -T 查 OOMdocker stats 查容器内存修复泄漏调整 JVM 堆或容器内存 limit磁盘容量没满但创建文件失败inode 被小文件耗尽df -i清理小文件调整日志轮转策略磁盘写入很慢服务整体卡顿磁盘 IO 打满或软 RAID 降级iostat -x 1cat /proc/mdstat定位写入进程检查阵列状态扩容或更换磁盘SSH 连接经常断开网络丢包、sshd 并发限制、DNS 反查慢ping 查丢包ssh -vvv 看阶段优化 sshd_config检查客户端网络服务偶发无响应重启后恢复资源耗尽后进程被系统杀掉journalctl -k 查 OOM按第 3-5 节方法与顺序定位资源瓶颈日志时间线和实际不一致NTP 未配置或校时端口不通chronyc sources -v配置 chrony开放 UDP 123 端口TCP 重传多客户端频繁超时链路丢包、带宽打满、防火墙限流netstat -s 查重传ethtool -S 查网卡联系网络服务商调整 QoS 和限流这个表只覆盖了最常遇到的几个场景。实际生产中问题可能是多个根因叠加引起的比如内存泄漏导致服务变慢服务变慢导致线程堆积线程堆积导致 CPU 升高最终整个链路雪崩。所以排查时要保持“先止损、后定位”的思路而不是试图一次找到所有原因。9. 生产环境稳定性治理最佳实践9.1 先止损再排查生产环境出现不稳定时第一目标不是立刻找出根因而是恢复业务。盲目在一台快挂掉的服务器上执行各种排查命令不仅危险还可能加剧问题。合理顺序是先确认业务影响范围然后根据情况选择重启单实例、切换流量、扩容新实例或回滚最近变更待业务稳定后再回头分析根因。重启有讲究不建议在同一时间把所有实例全部重启应该采用滚动重启每次只重启一部分观察业务是否恢复再做下一步。如果怀疑是最近发布导致的问题优先回滚而不是继续调优。止损和排查可以并行但止损永远拥有更高优先级。9.2 自动化巡检与告警服务器不稳定很多情况下是可以提前发现的。以最开始提供的server_check.sh为例可以把它加入 crontab定期执行并留档# 每 5 分钟执行一次日志保留在 /var/log 目录 */5 * * * * /usr/local/bin/server_check.sh /var/log/server_check.log 21但巡检脚本只能提供快照真正的稳定性治理需要持续监控和告警。建议至少覆盖以下指标CPU 使用率、平均负载、内存 available、磁盘使用率、inode 使用率、磁盘 IO 延迟、网络丢包率、TCP 重传率、进程存活状态。监控不是为了在故障后看回放而是为了在故障前收到告警。对于个人项目可以先用简单的 shell 脚本加邮件通知对于团队项目建议搭建完善的监控告警体系。9.3 容量规划与架构冗余稳定性不只是排查问题更是提前避免问题。容量规划的关键是给关键资源留足余量通常建议 CPU、内存、磁盘使用率达到 60% 到 70% 时就考虑扩容或清理而不是等到 90% 再处理。带宽和连接数也要做容量评估业务增长时及时扩容。架构层面尽量消除单点。使用负载均衡对外提供服务数据库做主从或高可用集群缓存和消息队列做集群部署。需要考虑的一个问题是引入集群后虽然提升了可用性但也引入了新的不稳定因素比如集群节点时钟不同步、脑裂、配置不一致等。架构越复杂对监控和变更管理的要求就越高。对于 Web 服务器安全不要只关注性能。定期更新系统补丁关闭不必要的服务端口限制 SSH root 远程登录使用密钥认证代替密码登录配置防火墙最小开放原则这些都属于稳定性的基础工程。安全事件是造成服务器不稳定的一个非常常见的诱因被植入挖矿程序后CPU 经常飙到 100%这种不稳定不是资源规划能解决的。GPU 服务器是另一个需要单独关注的方向。训练任务表现不稳定时除了常规的 CPU、内存、磁盘还要关注 GPU 温度和显存占用。执行nvidia-smi可以看到 GPU 利用率、显存、温度、风扇转速以及 ECC 错误计数。如果 ECC 错误持续增长说明 GPU 硬件可能存在问题。多卡训练还要检查 NVLink 或 PCIe 链路状态。GPU 服务器的运维重点在于驱动版本、CUDA 版本、显存清理和温度控制这些内容值得单独写一篇文章。9.4 变更管理与可观测性最后强调两点第一所有变更必须可回溯第二所有关键路径必须可观测。可回溯意味着你能回答“这台服务器的配置昨天是什么样今天改了什么为什么改”。可观测意味着当链路某个环节变慢时你能快速判断是应用问题、数据库问题还是基础设施问题。对个人开发者来说即使没有团队也建议养成写变更日志的习惯。很多“莫名其妙”的不稳定在记录变更之后都会变得“有迹可循”。对团队来说则要建设好日志聚合、链路追踪和监控告警三条核心能力。这类基础设施建设看起来投入大但每一次故障排查中节省的时间都会成倍回报回来。排查不稳定服务器的方法到这里已经完整串联起来了从准备监控和时间同步开始依次检查 CPU 和负载、内存与 OOM、磁盘容量与 IO、网络与连接再结合虚拟化和云服务器的特殊场景最后用变更记录和容量规划来防止问题复现。与其收藏这篇文章不如先把文中那个简易巡检脚本放到服务器上跑一次等下次服务器再次露出“不稳定的统治”苗头时你至少已经有了可以按顺序出牌的底牌。