别再重启了。先检查这些地方!
如果你长期运行 Linux 系统,迟早会遇到这样一个状况:
服务器“很慢”,但“一切正常”
此时,**sudo reboot** 的冲动正强烈地攫住你的心神。
重启意味着我们不理解问题
重启在 Linux 语境下,等同于说:
“我不理解这个问题,但我希望它消失。”
它是在凌晨 3 点“止血”的最快方法,但也保证了根本原因还会再次出现。在生产环境中,重启很少是首选的最佳方案。
正常运行时间是金科玉律
在生产环境中,保持系统可用性始终优先于完美的修复或严谨的实验。用户不关心我们的解决方案有多精巧,他们只关心服务是否正常运行。
我们只在没有其他更安全的选择时才重启。
观察,而非中断
重启是终极中断。它会销毁所有运行时状态,中断所有活动连接,并且通常只是掩盖而非解决潜在问题。
生产环境下的调试,与其说是进行重大更改,不如说是仔细观察、隔离问题,并仅修复必要的部分。
#1. 从内核视角入手
在深入查看日志或归咎于应用程序之前,让我们先问一个简单的问题:内核是否正承受巨大压力?
为了回答这个问题,我们可以通过以下命令检查系统负载:
# Output
14:22:01 up 120 days, 3 users, load average: 12.4, 10.8, 9.6
• **14:22:01** — 当前系统时间。
• **up 120 days** — 这台服务器已经连续运行了约 4 个月(120 天),期间未曾重启。
• **3 users** — 当前登录到系统的用户数量(通过 SSH 或本地终端)。
• **load average: 12.4, 10.8, 9.6** — 表示过去三个不同时间间隔的平均系统负载: **12.4** : 过去 1 分钟 **10.8** : 过去 5 分钟 **9.6** : 过去 15 分钟
解读负载
负载是指正在使用 CPU 或处于等待 CPU(可运行状态)的进程数量,以及等待 I/O(例如从磁盘读取)的进程数量。
负载达到 12.4 “高”吗?这完全取决于我们拥有多少个 CPU 核心:
• 在 4 核系统上 — 负载达到 12 意味着系统大致以其 300% 的容量 运行,内核中有大量任务正在排队等待执行。
• 在 16 核系统上 — 同样的负载 12 仅达到约 75% 的利用率 ,这可能完全正常。
解读趋势
结合这三个数值,我们可以判断系统问题是在好转还是恶化:
• 1m > 5m > 15m — 负载正在升高,情况正在恶化
• 1m < 5m < 15m — 负载正在下降,系统正在恢复
• 1m ~ 5m ~ 15m — 负载保持一致(稳定)。
#2. 检查进程
一旦我们确定系统承受压力,接下来的问题就很明确了:哪个进程是导致问题的原因?
# Top 10 memory consumers
ps -eo pid,ppid,%cpu,%mem,rss,stat,wchan,cmd --sort=-%mem | head -10
# Top 10 CPU consumers
ps -eo pid,ppid,%cpu,%mem,rss,stat,wchan,cmd --sort=-%cpu | head -10
• **pid** — 进程 ID
• **ppid** — 父进程(有助于追溯其来源)
• **%cpu** — CPU 使用百分比
• **%mem** — RAM 使用百分比
• **rss** — 常驻内存大小 (Resident Set Size)(实际使用的内存量,单位 KB)
• **stat** — 进程状态。值得关注的状态包括: **R** : 运行态( 应用正在活跃地占用 CPU 资源 ) ** **S** : 休眠态(进程正在等待某个事件或锁) **D** : 不可中断睡眠(通常是在等待 I/O 操作) **Z** : 僵尸进程(已终止但尚未被父进程回收)
• **wchan** — 进程正在等待的内核函数
• **cmd** — 启动该进程的命令
不可中断睡眠
高负载不一定总是意味着高 CPU 使用率。通常情况下,它表示进程因等待磁盘、内存或其他 I/O 资源而被阻塞。
那么,根据我们的发现,究竟采取何种措施才能真正解决资源压力而不会引发更多问题呢?这并非简单地“盲目杀死进程”,而是取决于进程消耗资源的原因以及受压资源的类型。
CPU密集型进程 (CPU-bound process) (高 %CPU, 状态 R)
调查其消耗 CPU 的原因 (例如,无限循环、低效代码、繁重计算)。可采取的措施包括:
• 如果进程卡顿,则重启该进程。
• 限制 CPU 使用 ( cpulimit 、 cgroups )。
• 优化应用程序或工作负载。
内存密集型进程 (Memory-bound process) (高 %MEM 或 RSS)
检查是否存在内存泄漏或异常大的工作负载。可采取的措施包括:
• 重启进程以释放内存。
• 调整应用程序内存设置 (如堆大小 (heap size)、缓存限制)。
• 如果工作负载属于正常范畴,则增加 RAM。
I/O密集型 / 阻塞进程 (I/O-bound / blocked processes) (D 状态 (D state),wchan=io_schedule)
瓶颈在于存储,而非应用程序本身。可采取的措施包括:
• 检查磁盘吞吐量、延迟或是否存在错误。
• 优化数据库写入或批处理操作。
• 如果系统持续出现阻塞情况,则升级存储。
• 在 I/O 操作完成之前,杀死 D 状态进程通常 无济于事 。
僵尸进程 (Zombie processes) (Z 状态 (Z state))
• 识别父进程并确保其能正确回收子进程。如果问题持续存在,则重启父进程。
正常但繁重的工作负载
有时高资源使用属于预期情况。可采取的措施包括:
• 调优或扩展系统 (例如,增加 CPU、RAM 或采用更快的存储)。
• 在非高峰时段安排繁重任务。
#5. 监控与预防
监控和自动化是保持系统健康、避免停机时间以及及早发现问题的关键。
• CPU 使用率 (CPU usage) — 识别失控进程 (runaway processes) 或持续高 CPU 使用率,这可能表明存在 Bug 或繁重的工作负载。应同时跟踪总 CPU 使用率和每个进程的 CPU 消耗。
• 内存使用率 (Memory usage) — 密切关注总 RAM、交换内存使用以及每个进程的内存 (RSS)。内存突然飙升可能预示着内存泄漏或应用程序效率低下。
• I/O 性能 (I/O performance) — 监控磁盘读写速度、延迟和队列。长时间处于 D 状态 (D state) 的进程通常表明存在存储瓶颈。
• 负载平均值 (Load averages) — 将系统负载与 CPU 核心数进行比较。持续负载高于核心数可能表明 CPU 饱和。
• 进程状态 (Process states) — 跟踪 D 状态 (阻塞 I/O) 和 Z 状态 (僵尸) 进程。此类进程的堆积可能预示着底层性能或应用程序问题。
警报与阈值
设置可操作的告警阈值,以便在资源紧张时我们就能收到通知,而不是等到系统变慢后再去应对:
• CPU 告警: 当 CPU (Central Processing Unit) 使用率持续超过 80% 到 90% 时触发。
• 内存告警: 当内存 (Memory) 使用率高于 85%,或者交换分区 (Swap) 开始增加时发出警告。
• I/O 告警: 当 I/O (Input/Output) 等待时间超过 20% 到 30%,或者磁盘延迟 (Disk Latency) 激增时发出通知。
• 进程告警: 检测是否有多个进程 (Process) 停留在 D 状态(不可中断睡眠),或僵尸进程 (Zombie Process) 大量累积。
结语
借助正确的工作流程和工具,我们可以在不立即重启服务或系统的情况下,排除并解决大多数问题。通过深入检查进程、理解其状态并分析资源使用情况,我们通常可以识别出根本原因,并采取有针对性的纠正措施,从而在保持系统平稳运行的同时,最大限度地减少用户的停机时间与业务中断。
感谢阅读!希望本文能帮助大家在下次生产环境 (Production Environment) 出现异常时,保持冷静并从容应对。学习、分享、影响!