所谓“不稳定服务器的统治”,其实是运维人的一种自嘲:你永远不知道下一次事故是 CPU 飙高、磁盘只读、时间漂移,还是 SSH 突然连不上。它不会一次崩得彻底,而是高强度地折磨你——白天好好的,晚上高峰一到就发飘;重启能顶两天,过几天又犯病。这篇文章是这个系列的第二季,我直接把服务器不稳定最常见的场景一次性捋清楚:现象对应什么根因、先查哪里、用什么命令、怎么验证、怎么防止再犯。
文章不绑定某个云厂商,也不纠结某个 Linux 发行版,而是从服务器运维的通用视角出发,按系统层、磁盘层、网络层、时间同步、虚拟化与云服务器、服务与接口稳定性几个方向展开。无论你是刚接手服务器的运维新人,还是自己用云服务器搭过博客、NAS、集群的开发者,这套排查思路都可以直接照抄到自己的环境里。
先给一个安全前提:文中所有命令都建议在测试环境或你拥有维护权限的服务器上执行;涉及生产环境操作,先备份、走变更窗口,不要在不了解后果的情况下直接重启服务或关闭防火墙。文章较长,但每一步都能落地,建议边看边在测试服务器上验证。
1. 不稳定服务器核心问题速览
先把最常见的“服务器不稳定”现象和排查方向汇总成一张表,后面每一节都会展开讲命令和判断标准。这张表适合贴在工位旁边,遇到问题先对号入座。
| 不稳定表现 | 常见根因 | 第一诊断命令 | 快速处理方向 |
|---|---|---|---|
| 服务器负载高、操作卡顿 | CPU 跑满、内存不足、IO 等待高 | top、vmstat、iostat | 定位进程、优化代码或扩容 |
| SSH 连不上或间歇掉线 | 网络不通、防火墙拦截、sshd 异常 | ping、ssh -v | 检查网络链路和 sshd 状态 |
| 服务器时间不准 | NTP 未配置、UDP 123 端口不通 | timedatectl、chronyc tracking | 配置可用的时间服务器 |
| 磁盘空间消失或文件只读 | 磁盘写满、inode 满、文件系统故障 | df -h、df -i、dmesg | 清理磁盘、修复前先备份 |
| 服务莫名其妙重启 | 内存溢出 OOM、systemd 重启策略、内核崩溃 | dmesg、journalctl -u 服务名 | 调内存、改重启策略、修配置 |
| 接口间歇性超时 | 后端连接数满、DNS 解析慢、云资源被限流 | curl -w、ss -s、dig | 扩容、调参数、缓存 DNS |
这套对应关系是排障的第一层,真正定位问题时还要结合日志和监控。下面按层拆解,每一层都有可复制的命令。
2. 适用场景与使用边界
这篇文章面向三类人:第一类是刚入门服务器运维的技术人员,需要一套从现象到根因的完整排查思路;第二类是自建服务的开发者,服务器上跑着 Web 服务、数据库、NAS 或者集群,想解决“不稳定”但不知道从哪下手;第三类是准备做服务器部署和集群方案的人,需要避开时间不同步、健康检查失效这些隐藏坑。
同时要说明使用边界。排查服务器不稳定,本质上是在操作线上或半线上的系统,有几点必须遵守:第一,只排查你拥有所有权或明确维护授权的服务器,不要对不属于自己的系统执行任何扫描或测试;第二,任何停机类操作,比如重启服务、卸载软件、重挂载磁盘,都要先备份配置和数据,并选择低峰期执行;第三,排查网络问题时,不要把“临时关防火墙”变成长期操作,改完规则后要确认是放行指定端口,而不是全部放开;第四,涉及数据库、用户数据、日志时,注意隐私和数据合规,不要随意导出敏感信息。
3. 环境准备:诊断工具箱和前置条件
进入实战前,先确认服务器的基础信息。你至少需要 SSH 访问权限,并且有一个可以使用 sudo 的账号。先看系统类型、内核版本和运行时长。
cat /etc/os-release uname -a uptimeuptime里的 load average 是第一个线索:如果 1 分钟负载明显高于 5 分钟和 15 分钟,说明系统是最近才开始变忙;如果三个值都很高,说明已经持续一段时间了。
接下来安装诊断工具。工具不在多,够用就行:
# Debian / Ubuntu sudo apt update sudo apt install -y sysstat procps iproute2 dnsutils curl lsof chrony # CentOS / RHEL / Rocky Linux sudo yum install -y sysstat procps-ng iproute dnsutils curl lsof chrony这几个工具覆盖了日常排障的大部分场景:sysstat提供sar、iostat、mpstat,iproute2提供ss,dnsutils提供nslookup和dig,lsof用来查端口和进程占用。如果你的发行版已经预装了其中一部分,跳过即可。
建议顺手做一件事:用下面的命令记录一份“正常状态基线”。没有基线,就不容易判断负载 3.0 到底是正常还是异常。
# 记录当前 CPU、内存、磁盘状况,作为后续对比基线 date "+%Y-%m-%d %H:%M:%S" uptime free -h df -h3.1 关于 Windows 服务器的补充
材料里也提到了 Windows 服务器场景。Windows Server 的排查思路和 Linux 一致,只是工具不同:用任务管理器看 CPU 和内存,用资源监视器看磁盘和网络,用“事件查看器”的“系统”日志看内核级报错。Windows 时间服务可以用w32tm /query /status查看同步状态。后面的章节我会以 Linux 为主,但每个方向都会带一句 Windows 的对应检查项。
4. 系统层排查:CPU、内存与负载异常
系统层不稳定是最容易观察到的,表现就是卡、慢、负载高。这里先分清三种情况:CPU 忙、内存不足、IO 等待高。三种情况的处理方式完全不同,先诊断再动手。
4.1 负载与 CPU 排查
top是最直接的入口。按P键按 CPU 排序,看哪个进程在消耗 CPU;按M键按内存排序,看哪个进程吃内存最多。重点看两列:每核 CPU 使用率和进程状态。如果大量进程处于D状态,也就是不可中断睡眠,通常是在等磁盘 IO,单纯加 CPU 是没用的。
# 每 2 秒刷新一次 vmstat,观察 r(运行队列)和 b(阻塞进程) vmstat 2 5 # 查看历史 CPU 使用率,判断是偶发还是持续 sar -u 1 3 # 找出 D 状态进程 ps -eo state,pid,cmd | grep '^D'vmstat 的输出里,r列表示正在运行的进程数,一般不应持续超过 CPU 核心数的 3 到 4 倍;b列如果有值,说明有进程阻塞,优先查磁盘。si和so如果长期不为 0,说明内存在频繁换页,下一步就查内存。
4.2 内存与 OOM 排查
内存不足的典型表现是:服务还在,但响应很慢;或者服务直接消失,然后 systemd 把它拉起来。先看内存总量和 swap 使用情况:
free -h # 检查内核是否发生过 OOM 杀进程 dmesg -T | grep -i -E "out of memory|killed process"如果free显示内存还剩很多但系统还是卡,不要急着加内存,先看是不是 IO 或网络问题。如果 dmesg 里出现了Out of memory: Killed process,说明某个进程吃满了内存被内核干掉了。此时要定位为什么内存会爆:是配置把堆内存调太大,还是存在内存泄漏。临时可以调高 swap,但根治方向是修程序或加内存。
5. 磁盘层排查:IO 等待、磁盘阵列与文件系统
磁盘问题最喜欢伪装成“服务器变慢了”。负载不高、CPU 不高,但服务就是慢,这时候八成在看磁盘。
先做两个最基础的检查:空间是否写满,inode 是否耗尽。
df -h df -idf -h显示磁盘空间使用率,df -i显示 inode 使用率。很多人只盯空间,忽略了小文件过多导致 inode 耗尽的情况。inode 满了的表现是:磁盘明明有空间,但新建文件提示No space left on device。
再看磁盘 IO 是否有瓶颈:
# 观察 %util 和 await,需要 sysstat iostat -x 1 3%util接近 100% 说明磁盘已经很忙,await表示 IO 请求的平均等待时间。如果await很高但%util不高,可能是单个请求本身太慢,需要看磁盘健康状态;如果两者都高,就是吞吐不够,要考虑清理日志、优化查询,或者换更高 IOPS 的磁盘。
磁盘阵列方面,软件 RAID 可以直接看状态:
cat /proc/mdstat如果看到[UU]之外的标记,比如[U_]或recovering,说明阵列有磁盘掉线或正在重建。硬件 RAID 需要用厂商工具查看,这个没法给通用命令,但思路一致:登录阵列管理界面或使用storcli/megacli查看硬盘状态和告警信息。阵列降级运行的服务器会伴随 IO 性能下降,这也是“不稳定”的常见来源。
文件系统突然变成只读,是服务器不稳定的一个高危信号。表现为进程报错Read-only file system。先用dmesg -T | tail -50看内核日志,确认是文件系统错误还是硬件 IO 错误。不要直接mount -o remount,rw /强行恢复,那样可能掩盖真实故障。正确做法是先备份数据,再通过fsck检查修复,修复前必须确认磁盘是卸载状态或只读挂载状态。
Windows 服务器的对应检查是:事件查看器里的磁盘事件、wmic diskdrive get status查看磁盘健康状态、fsutil volume diskfree C:查看空间。
6. 网络层排查:连接、端口、DNS 与远程连不上
网络层的不稳定表现最多:SSH 连不上、端口访问不了、接口超时、DNS 解析慢。这一层的问题往往会同时影响多个服务,排查优先级很高。
6.1 SSH 连接失败排查
遇到 SSH 连不上,先分层定位。ping不通,是网络层问题,查安全组、防火墙、物理链路;ping通但 SSH 连不上,可能是 22 端口被拦截或 sshd 异常。用ssh -v能看到详细的握手过程:
ssh -v user@your-server-ip如果卡在Connection timed out,基本是防火墙或安全组问题;如果能到Authentications that can continue,说明网络是通的,问题在认证或 sshd 配置。VSCode 远程 SSH 连接失败也算同类问题,排查思路一样:先在终端用ssh -v复现,确认能否手动登录,再看~/.ssh/config的 Host 配置和known_hosts是否冲突。很多时候 VSCode 报错信息很笼统,但ssh -v的输出已经把原因写得很清楚了。
6.2 端口与连接状态排查
服务端口访问不了,按这个顺序查:服务是否在监听、端口是否被占用、防火墙是否放行。
# 查看端口监听情况 ss -lntp # 只看某个端口 ss -lntp | grep ':8080 ' # 查看具体进程占用 lsof -i :8080如果端口根本没有监听,说明服务没起来或启动失败,去查服务日志;如果端口被别的进程占了,那就是冲突,需要改端口或停掉占用进程;如果监听正常但外部访问不了,检查防火墙和云安全组。云服务器尤其要留意:很多“端口不通”其实是安全组没放行,和服务器本身没关系。
6.3 DNS 与远程请求失败
接口间歇性超时,有时候不是应用问题,而是 DNS 解析变慢。系统里每解析一次域名都要请求 DNS 服务器,如果 DNS 服务器不稳定,服务就会时快时慢。
cat /etc/resolv.conf nslookup your-service.example.com dig your-service.example.com观察dig输出的查询时间和服务器地址。如果解析时间忽高忽低,考虑在应用层加 DNS 缓存,或者改为 IP 直连测试对比。Windows 环境下用 PowerShell 执行远程请求时报“无法连接到远程服务器”,除了检查目标地址连通性,还要看 TLS 版本、系统代理设置和防火墙规则。可以先用curl.exe -v代替 PowerShell 复现一次,快速区分是网络问题还是 PowerShell 自身组件的问题。
7. 时间同步排查:NTP、时区与 123 端口
时间同步是服务器不稳定里最容易被忽略的原因。服务器时间漂移会导致 TLS 证书校验失败、集群节点间认证失败、日志时间对不上、定时任务乱跑。如果你发现服务日志时间“穿越”了,或者 HTTPS 请求突然报证书错误,第一件事就是查时间。
# 查看当前时间、时区和时间同步状态 timedatectl # 使用 chrony 时查看同步源 chronyc sources -v chronyc tracking # 检查本机 123 端口是否在监听(UDP) ss -unap | grep ':123 'timedatectl输出里的System clock synchronized如果显示no,说明系统根本没有成功同步时间。chronyc sources里看同步源的标记,正常状态应该是^*,表示当前使用该源同步;如果显示^?或没有可用源,说明 NTP 请求发不出去。
NTP 使用 UDP 123 端口。很多服务器能上网,但 123 端口被防火墙拦了,导致时间一直同步不上。检查防火墙时注意,NTP 是 UDP 不是 TCP,别只放行 TCP。配置 chrony 的方式很简单:
# /etc/chrony/chrony.conf 示例 pool pool.ntp.org iburst # 国内网络环境建议就近选择时间服务器池,例如: # pool ntp.aliyun.com iburst # 允许本机同步,不对外提供服务 local stratum 10改完配置后执行:
sudo systemctl restart chronyd timedatectl set-ntp true chronyc sources -v等几秒再chronyc tracking,看到Leap status : Normal且System time偏差缩小时,说明同步恢复。时间偏差较大的服务器,不建议一次性大幅跳变时间,避免对数据库和正在运行的任务造成冲击。Windows 服务器用w32tm /query /status和w32tm /resync做同类操作。
集群场景下,时间不同步的危害会被放大:所有节点必须指向同一套时间源,否则分布式协调、日志归集、数据一致性都会出问题。部署集群前就要把时间同步纳入初始化脚本。
8. 虚拟化与云服务器场景:被共享资源拖垮的服务器
如果你用的是云服务器,或者服务器跑在 KVM 等虚拟化平台上,“不稳定”的原因可能不在你机器内部,而在宿主机。共享资源的竞争是云服务器不稳定的重要来源。
先看 CPU 的 steal 时间。steal 表示虚拟机等待宿主机分配 CPU 的时间,数值越高,说明宿主机资源越紧张,你的云服务器在“排队”。这是本地物理机不会遇到的问题。
# 观察 %st 列,mpstat 需要 sysstat mpstat -P ALL 1 3 # 或者在 top 里一直按 1,展开每个 CPU 的统计 top如果%st长期超过 10%,说明云服务器所在宿主机已经过载,代码层面优化效果有限,优先考虑迁移实例或升级规格。免费云服务器尤其容易出现这类问题,因为这类实例普遍是共享资源,CPU 峰值、带宽、IOPS 都有严格限额,业务一上来就会触发限流,表现就是接口时快时慢。
KVM 虚拟化环境下,还要检查虚拟机的驱动和内核日志:
# 查看内核日志中的虚拟化相关报错 dmesg -T | grep -i -E "virtio|kvm|watchdog"如果看到大量watchdog或设备超时报错,可能是宿主机 IO 调度问题,也可能是虚拟磁盘驱动没装好。使用 KVM 给服务器做系统时,建议安装对应的 virtio 驱动,否则磁盘和网络性能会明显偏低,并且容易在负载升高时出现不稳定。
服务器集群的不稳定,不完全等同于单节点不稳定。集群里常见的是“某个节点掉队”:健康检查失败、节点时间漂移、网络分区。排查时不要只盯出问题的节点,还要看负载均衡的健康检查配置和每个节点的时间同步状态。健康检查探针本身的超时时间设置不合理,也会造成“后端明明活着,但被摘除”的假故障。
9. 服务与接口稳定性:日志、systemd 与探活脚本
前面几层查完,如果系统资源都正常,那问题大概率出在服务本身或服务依赖上。这时候要看两个东西:服务日志和 systemd 状态。
# 查看服务运行状态和最近日志 systemctl status myapp # 只看最近 10 分钟的服务日志 journalctl -u myapp --since "10 minutes ago" # 跟踪最新日志 journalctl -u myapp -fsystemd 管理的服务如果配置了Restart=on-failure,服务崩了会被自动拉起。这本身是好事,但也会掩盖问题:如果服务一直在崩溃重启,你看到的状态永远是active (running),但业务其实一直在断。判断方法很简单,看服务的Main PID是否频繁变化,或者用systemctl show myapp -p NRestarts查看重启次数。
一个标准的服务配置参考:
# /etc/systemd/system/myapp.service 示例 [Unit] Description=My App Service After=network.target [Service] ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml Restart=on-failure RestartSec=5 Environment="GOMAXPROCS=2" [Install] WantedBy=multi-user.target写完配置后执行sudo systemctl daemon-reload再启动服务。给服务加上健康检查探活,是判断接口稳定性的最直接手段。下面是一个最小可用的探活脚本:
#!/usr/bin/env bash # 接口探活脚本:探测服务健康接口,失败时输出状态 url="http://127.0.0.1:8080/health" code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "$url") if [ "$code" = "200" ]; then echo "[OK] $(date '+%Y-%m-%d %H:%M:%S') $url -> $code" exit 0 else echo "[FAIL] $(date '+%Y-%m-%d %H:%M:%S') $url -> $code" exit 1 fi把这个脚本加入 crontab,每分钟执行一次,输出重定向到日志文件,再配合简单的日志告警,就能第一时间知道接口状态。用 Python 写效果类似,适合要接告警通知的场景:
import requests url = "http://127.0.0.1:8080/health" try: resp = requests.get(url, timeout=5) if resp.status_code == 200: print("[OK]", resp.status_code) else: print("[FAIL]", resp.status_code) # 这里可以接企业微信、钉钉或邮件通知 except requests.RequestException as exc: print("[FAIL]", exc)日志管理也要跟上。日志文件无限增长会占满磁盘,很多“服务器突然不稳定”其实是日志把磁盘写满了。配置 logrotate 按天或按大小切割日志,保留最近几份,是必须做的事。
10. 常见问题与排查方法对照表
把前面所有章节浓缩成一张表,遇到问题直接查对应行。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 服务器负载持续升高 | 业务流量增长、死循环进程、IO 等待 | top、vmstat、iostat | 定位进程,优化或扩容 |
| SSH 连接超时 | 安全组未放行、防火墙拦截、sshd 未启动 | ping、ssh -v、systemctl status sshd | 调整防火墙规则,启动 sshd |
| VSCode 远程 SSH 连不上 | SSH 配置错误、known_hosts 冲突 | 终端执行ssh -v复现 | 修正~/.ssh/config,清理 known_hosts |
| 服务器时间不准 | NTP 未配置、UDP 123 端口不通 | timedatectl、chronyc sources -v | 配置时间服务器并重启 chronyd |
| 磁盘空间充足但写不进文件 | inode 耗尽 | df -i | 清理大量小文件 |
| 文件系统只读 | 文件系统错误、硬件 IO 故障 | dmesg -T | 备份后修复,必要时更换磁盘 |
| 端口访问不了 | 服务未启动、端口被占用、防火墙拦截 | ss -lntp、lsof -i :端口 | 启动服务、换端口或放行规则 |
| 服务频繁重启 | OOM、配置错误、依赖未就绪 | dmesg、journalctl -u 服务名 | 调内存、修复配置、加依赖等待 |
| 接口间歇性超时 | 连接数满、DNS 慢、云资源限流 | ss -s、curl -w、dig | 扩容、调连接数、缓存 DNS |
| 云服务器 CPU 高但本机无大进程 | 宿主机资源争抢 | mpstat观察%st | 迁移实例或升级规格 |
| PowerShell 远程请求失败 | TLS 版本、代理、网络策略 | curl.exe -v复现 | 更新系统组件、配置代理 |
| RAID 阵列降级 | 磁盘掉线 | cat /proc/mdstat、厂商工具 | 更换磁盘,重建阵列 |
这张表覆盖了服务器运维里最常见的“不稳定”场景。如果你遇到的问题不在表里,回到日志和监控两条主线,基本都能找到线索。
11. 最佳实践与使用建议
排查不稳定服务器,最忌讳的是“每次重来一遍”。这里分享几条能长期受益的实践。
第一,建立基线。把服务器正常状态下的 CPU、内存、磁盘、带宽记录成文档,后续所有告警都对照基线判断。没有基线,你很难区分“负载 3 是异常”还是“负载 3 本来就是这样”。
第二,监控要从第一天就做。最少要在服务器上部署一个简单的采集脚本,记录 CPU、内存、磁盘、流量数据,保留至少两周。没有历史数据,问题复现时只能靠猜。等排查手段成熟后,再考虑升级到 Prometheus 加 Grafana 那套完整方案。
第三,变更要有回滚方案。服务器不稳定经常发生在某次变更之后:升级了软件、改了配置、加了定时任务。每次变更前写清楚变更内容、影响范围、回滚方式,出问题直接回滚,比现场 debug 快得多。
第四,保留一套最小可运行配置。把服务能跑起来的最简配置单独存档,不要和线上复杂配置混在一起。出问题时,可以快速用最小配置验证是配置问题还是环境问题。
第五,排查过程和结果要留档。每次处理完一次事故,把现象、命令输出、根因、解决方案写进团队文档,整理成运行手册。下次同类问题出现,直接翻手册,不需要重新回忆命令。
合规方面再强调一次:操作服务器前确认授权范围,涉及人脸、声音、用户数据、版权素材的内容必须确认合法来源和授权;不要在未经允许的系统上运行扫描和测试脚本;生产环境的防火墙和访问控制只做最小放行,排查完及时恢复。
这套从系统层、磁盘层、网络层、时间同步、虚拟化到服务层的排查流程,建议直接保存成一份 runbook。下一次服务器再“犯病”,把每一层的诊断命令按顺序跑一遍,输出结果存好,你会发现自己处理不稳定服务器的效率比原来快很多。