资讯动态

系统基础总结:CPU、内存、IO、网络五条主线与排障实战

发布时间:2026/10/15 6:14:36 来源:尧图企业网站定制
“系统基础总结”这四个字我在刚入行的时候觉得它最没意思教材里写着冯诺依曼结构、进程线程、内存分页背完就忘工作里好像也用不上。直到有次线上接口无故变慢我把日志、代码翻了个底朝天都没找到原因最后用系统命令看了一眼 IO 等待和上下文切换才发现是磁盘线程被打满那一刻才明白所谓系统基础本质是一套描述“计算机这台机器到底怎么运转”的通用语言不会它你连问题出在哪一层都说不清楚。这篇文章想把“系统基础”拆成 CPU、内存、进程、文件系统与 IO、网络协议栈五条主线每条线讲清楚原理再用一组命令把它们验证一遍最后给一个模拟排查实录。适合刚工作一两年、被线上问题追着跑的开发和运维也适合写了多年业务代码、想补底层课的老工程师。我不打算罗列概念而是按“先懂机制再看指标最后动手排障”的顺序走保证你看完能直接用。1. 内容整体设计与思路拆解1.1 系统基础的范围别把“基础”理解窄了很多人一提“系统基础”第一反应是《操作系统原理》课本进程、线程、死锁、页面置换。这些当然重要但仅靠它们构不成完整的排障能力。一个请求从客户端发出到服务端返回中间至少要经过网卡中断、协议栈处理、socket 队列、进程调度、用户态业务逻辑、文件读写、页缓存、磁盘调度等多个环节任何一个环节出问题表现都是“系统慢”。所以我把“系统基础”定义成五条线CPU 调度与进程模型、内存管理、文件系统与存储 IO、网络协议栈以及它们之上的观测手段。每一线又分三个层次第一层是机制知道它怎么设计的、为什么这么设计第二层是指标知道用哪个命令、看哪个字段能反映机制是否健康第三层是动作知道指标异常时下一步该做什么。多数人只停留在第一层把“基础”窄化成了概念背诵遇到实际问题照样无从下手。1.2 为什么必须动手验证说个我自己的经历。早年我以为 load average 就是 CPU 使用率后来发现机器 CPU 空闲但 load 很高才去查可运行队列和不可中断睡眠原来 load 统计的是“处于可运行或不可中断状态的进程数”磁盘卡住也会拉高 load。这种偏差靠看书纠正不了必须自己用负载工具压一台机器看着负载曲线抬起来再用 vmstat 观察进程状态列才能建立真正的体感。所以这篇总结的编排逻辑是“机制——指标——动作”循环每讲一个概念马上接一个命令去观测它再给一个真实场景让它落地。后面第 3 章和第 4 章就是这套方法的完整演示你可以把命令复制到自己的 Linux 机器上跟着敲效果比读十遍书都好。2. 核心机制梳理五条主线一次打通2.1 CPU 调度与进程模型一切延迟的起点CPU 是计算机最核心的资源但“CPU 忙”和“系统慢”之间并不是直接等号。操作系统为每个线程维护运行队列调度器按策略给线程分配时间片Linux 默认的 CFS 调度器用虚拟运行时间保证公平优先级高的进程会获得更多运行机会。线程在运行Running、可运行Runnable、睡眠Sleeping、不可中断睡眠Uninterruptible Sleep之间切换时都要发生上下文切换即保存当前线程的寄存器、程序计数器、栈指针再加载下一个线程的现场。上下文切换本身是有代价的。如果机器上线程数远大于 CPU 核数CPU 大量时间耗在“换人”而不是“干活”上就会出现 CPU 使用率不算太高、但请求延迟很高的情况。这是排查性能问题最容易忽视的点你看到的是业务慢实际瓶颈是调度层面的过度竞争。所以看 CPU 指标时除了使用率还要关注运行队列长度、上下文切换速率这比单纯看百分比更能说明问题。2.2 内存管理从虚拟地址到物理页框进程看到的内存是一段连续的虚拟地址空间操作系统通过页表把它映射到物理内存的页框上。这种设计天然做了三件事隔离进程空间、允许物理内存碎片化、支持按需换页。按需换页的意思是进程访问某个地址时才分配物理页框如果物理内存不够内核会把不常用的页换出到交换分区等再次访问时换入。页表映射产生了两个经典问题。第一个是缺页异常Page Fault带来的延迟特别是主缺页Major Fault需要从磁盘读数据往往高达几毫秒到几十毫秒远比内存访问的纳秒级慢第二个是内存回收时的“抖动”当物理内存耗尽系统不停地把页换出换入CPU 全耗在磁盘 IO 上表现为 load 飙高、响应瘫痪。还有一个容易被误解的地方free 命令里显示的 “cached” 不代表内存“不够用”那其实是页缓存Page Cache专门用来缓存文件内容内存压力大时可以被回收所以看内存瓶颈不要只看剩余量要综合看换页、扫描速率和 OOM 事件。2.3 文件系统与存储 IOB树、页缓存与静默损坏文件系统把磁盘块组织成文件ext4、xfs 这类主流文件系统都使用 B 树及类似结构管理元数据。每次读写文件路径大概是VFS 层根据路径找到 inodeinode 记录文件的属性与数据块位置读数据时先看页缓存命中就直接返回未命中才发起磁盘请求写数据时先写入页缓存标记为脏页由内核后续刷盘除非主动调用 fsync 强制落盘。这套设计极大提升了性能也埋下两个常见坑。第一个是 fsync 误用很多人以为写完文件数据就到了磁盘但断电或宕机时脏页可能丢失数据库等系统必须用 fsync 保证持久性反过来如果业务代码里没必要的频繁 fsync每次写操作都可能被拖慢到磁盘延迟级别这就是“日志写两块盘”一类设计的原因。第二个是 IO 调度与队列深度机械盘、固态盘的 IO 特性完全不同随机小 IO 对固态盘还行对机械盘就是灾难。观测时要注意 IO 等待时间svctm/await和队列长度而不是只看读写字节数。2.4 网络协议栈收包路径里藏着多少排队网络基础不只是 TCP 三次握手。一个数据包到达网卡后会触发硬中断把数据拷入内核缓冲区然后软中断接手经过协议栈解析放入 socket 的接收队列应用再通过 read/recv 把它取到用户态。注意每个环节都有队列网卡 Ring Buffer、接收队列、发送队列。队列一满就开始丢包或退避。TCP 本身的拥塞控制、重传、Nagle 算法等都会影响“网络看起来通不通”和“网络实际快不快”。比如连接超时和连接拒绝是两个不同的故障信号拒绝通常说明端口上 accept 队列已满或服务未监听超时则往往涉及路由、防火墙、对端不可达。排查网络时光会 ping 远远不够要看 socket 状态分布、重传率、接收丢包数三层定位。这也是第 3 章命令演示里必须覆盖的内容。3. 实操环节用一组命令把抽象概念拉回地面3.1 CPU 与负载先分清使用率、负载和维护最常用的命令是 top 和 vmstat。登录一台机器后我习惯先用 uptime 看 load average它是最近 1、5、15 分钟的可运行进程数加不可中断进程数的平均。字段高不代表 CPU 忙先按 1 看每个核的使用率再用 vmstat 1 观察连续输出vmstat 1 5输出里的 r 列是运行队列长度b 列是不可中断睡眠进程数us/sy 分别指用户态和内核态 CPU 占比cs 是上下文切换次数in 是中断次数。正常情况下 r 列应小于核数cs 不应高得吓人。如果 r 很高但 us 不高通常说明有大量短任务在抢占调度如果 b 持续大于 0要怀疑磁盘 IO 或锁等待。这套字段是我每次排障的第一站它让你在动手查代码前先把问题限定到“CPU 逻辑层”还是“IO 等待层”。3.2 内存区分缓存、真实占用与泄漏看内存别只看 free 的 free 列。正确姿势是先理解 total、used、buff/cache 三者关系free -hused 是进程实际占用的物理内存buff/cache 是内核缓存可以回收。真正危险的是 available 列持续下降同时 swap 使用率上升、vmstat 的 si/so 非零。如果怀疑某个进程内存泄漏用 pidstat -r 或观察 /proc/PID/status 里的 VmRSS 是否单调上涨再用 pmap 看进程地址空间分布判断是堆、栈还是第三方库吃掉了内存。我曾经排查过一个问题业务进程内存曲线呈锯齿状上涨下降最后定位到是某个 SDK 无限制缓存日志对象GC 一触发就释放一批表面看是“内存抖动”实际是资源管理失控。3.3 IO 与文件系统从延迟到队列深度iostat 是 IO 观测的主力iostat -x 1重点看 %util、await、svctm 和 avgqu-sz。%util 接近 100% 只代表设备繁忙不一定代表到达瓶颈因为固态盘的并行能力很强await 是 IO 请求的平均等待时间包含排队时间和实际服务时间如果 avgqu-sz 很大而 await 很高大概率是设备队列堆积。另一个容易被忽略的地方是文件系统层inode 耗尽、文件打开数超限也会表现为“写不进去”。查这类问题用 df -i 看 inode 使用率用 ulimit -n 和 /proc/sys/fs/file-nr 看文件句柄是否触顶。IO 问题有个典型现场iowait 高、iostat 里磁盘 %util 满但业务代码里明明只是读一个小文件后来发现是页缓存没有命中冷数据被频繁重复读加上随机地址访问机械盘直接被打爆。3.4 网络socket 状态比 ping 重要得多排查网络连接问题ss 比 netstat 更好用输出更清晰、速度更快ss -s ss -antp第一行能看到整个系统的 socket 数量统计重点看 TIME_WAIT、ESTABLISHED、SYN_RECV 的数值。SYN_RECV 异常升高通常是半连接队列满服务端处理握手能力不足ESTABLISHED 数量远大于预期可能是连接泄漏。再配合 sar -n TCP,ETCP 1 看重传率配合 ethtool -S 看丢包计数基本能把问题从应用层拽到内核协议栈层。我曾经遇到一个“偶发超时”问题查代码、查数据库都没结果最后用 tcpdump 抓包发现是网卡出现大量 RX 丢包环形缓冲区大小不够加大 ring buffer 后问题消失。这种问题不抓协议栈根本看不到。4. 排查实战模拟服务 X 的系统级定位过程4.1 场景一CPU 使用率飙到 95% 却不响应某服务的容器 CPU 限制 4 核监控显示单核利用率接近满接口超时率上升。我的排查链路是这样的先 top 找到 CPU 最高的进程 PID再用 top -Hp PID 找到具体线程 TIDjstack 或 gdb 把线程的堆栈导出来看它在哪个函数里自旋。结果发现热点集中在内存分配器加锁的路径上大量线程并发 malloc/free 争同一把锁。定位后修复方案是改造对象复用引入线程本地缓存把频繁分配的小对象变成池化。这轮的启示是CPU 高不一定代表“计算量大”也可能是锁竞争造成的自旋空转就像高速公路上车多到互相挡道车速反而更慢。排查 CPU 问题时先定位到线程再看它到底在执行哪段代码别急着优化算法。4.2 场景二内存持续上涨但 reachable 对象不多另一个服务 RSS 从 2GB 一路涨到 6GB业务并没有明显流量增长。我数项检查先用 free -h 确认系统整体尚有内存排除页缓存误判再用 pmap -x PID 看每段地址空间的 RSS发现有一块 mmap 区域持续膨胀进入 /proc/PID/fd 看是否存在频繁写文件但未关闭的句柄结果是一个日志库把日志先写到 mmap 文件写满后没有正确回卷。后来定位到是日志滚动逻辑配置失效根本不存在传统意义的“内存泄漏”而是文件映射占了地址空间。这类问题的排查教训是内存上涨先分清“堆内存上涨”“mmap 映射上涨”“页缓存上涨”“swap 换出波动”不要一上来就套用 Java 堆泄漏的思路。用 /proc/PID/smaps 观察具体匿名映射和文件映射的大小比单纯看 RSS 更准确。4.3 场景三接口不慢整体却像泥潭最后这个场景很典型单个接口的耗时统计正常但网关层的整体 RT 却不断上升。我先看了 vmstat 的 cs 和 in 两列发现上下文切换次数高得异常再用 ps -L 查线程数发现业务进程起了上千个线程线程锁碰撞严重大量线程在等待条件变量。接着用 iostat 看磁盘无压力用 ss -s 看连接数正常基本锁定是线程过多导致的调度颠簸。处理办法是把线程模型改为线程池控制并发上限并调整锁粒度。这里我想强调一个排查顺序全局指标优先于局部指标系统指标优先于应用日志。如果一开始就去查某条链路的日志很可能被大量正常数据干扰先看系统的调度、内存、IO、网络四张表把问题框定在一两层内再深入具体代码效率高得多。5. 常见问题速查表与排查纪律5.1 高频故障速查症状可能原因优先命令与关注字段load 高但 CPU 使用率不高不可中断睡眠多磁盘 IO 慢vmstat 的 b、iostat 的 awaitCPU 使用率高且集中在 user业务计算密集或自旋锁top -Hp 找线程perf top 看热点CPU 使用率高且集中在 sys系统调用频繁、内核态开销大strace -c 统计系统调用内存 available 持续下降进程泄漏或缓存异常增长pidstat -r、smaps 中 RSS 变化swap 使用率上升物理内存紧张换页严重vmstat 的 si/so 是否持续非零IO 等待时间长磁盘队列堆积或冷数据反复读iostat -x 的 avgqu-sz、awaitSYN_RECV 增多半连接队列满、握手瓶颈ss -s、netstat -s 的 drop 计数大量 TIME_WAIT短连接多且未复用ss -antp 的套接字状态数量表格里的每一行都对应第 3 章的命令用法先用速查表命中方向再用具体命令验证比漫无目的地乱试快很多。5.2 排查前的三条纪律第一条纪律先看全局再看局部。不要因为业务日志报错就直接陷入代码逻辑先确认 CPU、内存、IO、网络四类系统指标有没有异常把问题边界画出来。第二条纪律一次只改一个变量。排查时如果想同时调整线程数、超时时间、缓存配置就很难判断哪一步生效我通常先记录现场指标快照再改动一个参数观察五分钟确认有效或无效再动下一个。第三条纪律保留现场证据。用 date 标注命令输出把日志、指标快照、tcpdump 抓包文件保存好很多时候最终定位靠的是对比故障前后数据而不是当时的直觉。6. 经验沉淀我自己是怎么持续补这块课的系统基础最忌讳“学一遍就以为会了”它更像一项需要持续训练的手艺。我现在的习惯是每接触一台新环境机器先用 uptime、free、iostat、ss 各看一眼建立“这台机器正常时的基线条”等到出问题时再对比基线条偏差最大的指标往往就是根因方向。这个方法帮我解决过不少“偶发慢请求”类问题因为偶发问题最怕的就是没有参照物。另外我会刻意拿一些压测工具制造问题再自己排查比如用并发请求打满线程池观察上下文切换和锁竞争用大量读小文件把页缓存打穿观察 iowait 变化。主动折腾比被动救火更能巩固理解。这些实践并不难难的是坚持把每个模糊概念都落地成一次命令输出或一次故障演练。等你积累到一定程度会发现所谓“系统基础”不再是需要背的知识点而是一套下意识就能用的排查直觉。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑