上一篇 下一篇 分享链接 返回 返回顶部

云服务器CPU不高但响应慢,如何结合可用内存、交换空间和进程占用定位瓶颈?

发布人:Minchunlin 发布时间:2026-09-29 14:15 阅读量:31
云服务器CPU不高但响应慢,如何结合可用内存、交换空间和进程占用定位瓶颈?

云服务器 CPU 使用率不高但响应慢,可能是哪些资源出现瓶颈?从内存角度排查,重点看业务变慢时的可用内存、缓存回收、交换活动、进程占用和 OOM 事件,而不是只看 CPU 百分比或 free 一列。若 MemAvailable 持续下降,同时 vmstat 的 si、so 持续有值,且这些变化与请求延迟、阻塞任务或内存压力指标升高的时间相吻合,内存压力或交换读写就值得优先排查。

先在业务变慢时采集一组低风险信息:

free -h
vmstat 1 10
swapon --show

单独看到 free 很低、缓存较大或 Swap 已使用,都不能直接认定内存是瓶颈。判断需要结合一段时间内的变化,并进一步确认是系统整体内存紧张、某个进程占用增长,还是容器或服务的内存上限触发。

先判断内存压力是否与响应变慢同时发生

在常见 Linux 系统中,free -h 会显示 total、used、free、buff/cache 和 available 等字段。排查时优先关注 available,而不是只看 free:

  • free 是当前未使用的物理内存。
  • buff/cache 是缓冲区和文件缓存等占用。Linux 会利用空闲内存缓存文件,缓存通常可在需要时回收,因此它较大本身不代表内存不足。
  • available 是系统预计可供新程序使用的内存,比单看 free 更适合判断当前是否有内存余量。
  • Swap used 表示已有部分内存页进入交换空间,不表示这些页面此刻正在频繁读写。

如果业务变慢时 MemAvailable 仍稳定,交换活动也不明显,不能因为 free 较低或 buff/cache 较大就判定内存不足。反过来,如果 MemAvailable 在慢请求期间持续下降,并伴随交换活动、进程阻塞或 OOM 事件,内存压力影响业务的可能性就更高。

buff/cache 也不等于可以瞬间全部释放的内存,其中包含不同类型的缓存和内核占用。不要把 free + buff/cache 简单当作完全可用内存,也不建议为了“腾内存”直接清理缓存。

区分“曾经用过 Swap”和“当前正在交换”

可以用以下命令查看交换空间:

swapon --show
cat /proc/swaps

交换空间要分别看已使用量和当前活动。已使用量只能说明部分页面曾被换出;要判断现在是否正在频繁交换,还要观察 vmstat 的 si、so:

vmstat 1 10

重点字段如下:

字段含义排查时如何理解
si从交换空间换入内存的数据量连续多个采样周期有值,说明正在发生换入
so从内存换出到交换空间的数据量连续有值,可能反映内存回收压力
b不可中断睡眠任务数量结合交换活动和 wa 判断是否有等待
waCPU 等待 I/O 的时间占比与 si、so 同时升高时,需关注页面读写等待
r可运行任务数量持续较高可能存在调度排队,但不能单独证明内存不足
free未使用内存量仅作辅助,不替代 MemAvailable

vmstat 的第一行在不少系统上反映启动以来的平均情况,判断当前变化时应重点看后续按间隔采集的行。若 si、so 持续出现非零值,同时 MemAvailable 下降、b 或 wa 升高,而且与请求延迟在时间上重合,才比较符合内存压力导致交换读写、进而拖慢请求的情况。等待页面换入的线程可能处于阻塞状态,不会持续消耗用户态 CPU,因此可能出现 CPU 不高但响应变慢。

若 Swap 已使用,但 si、so 长时间为零,MemAvailable 也稳定,可能只是之前被换出的冷页面尚未再次访问。这种情况不能仅凭 Swap 使用量判定为当前瓶颈。

较新的 Linux 内核还可能提供内存压力信息:

if [ -r /proc/pressure/memory ]; then
    cat /proc/pressure/memory
else
    echo "当前系统未提供 /proc/pressure/memory"
fi

其中 some 表示至少有部分任务因内存资源而停顿,full 表示更严重的整体停顿。不同系统和负载的正常水平可能不同,不宜套用一个固定阈值;应观察指标是否在业务变慢期间持续升高,并与 MemAvailable、交换活动和请求延迟对照。

从进程占用找出内存压力来源

确认系统有内存压力后,再定位哪些进程占用较多。以下命令适用于常见 Linux 环境,可按常驻内存初筛:

ps -eo pid,ppid,user,%mem,rss,vsz,stat,comm --sort=-rss | head -n 20
  • RSS 是进程当前驻留在物理内存中的大小,通常以 KB 为单位。
  • VSZ 是进程可见的虚拟地址空间大小,不能直接当作实际物理内存占用。
  • %MEM 表示进程占系统物理内存的比例。
  • STAT 中出现 D,通常表示进程处于不可中断睡眠;需要结合交换活动和其他等待情况判断原因。

RSS 适合初筛,但多个进程可能共享动态库、共享内存或文件页,直接相加可能高估实际消耗。需要进一步检查某个进程时,可读取其 /proc 信息:

PID=1234

grep -E '^(Name|State|VmPeak|VmSize|VmRSS|RssAnon|RssFile|RssShmem|VmSwap|Threads):' \
    /proc/"$PID"/status

if [ -r /proc/"$PID"/smaps_rollup ]; then
    grep -E '^(Rss|Pss|Pss_Anon|Pss_File|Pss_Shmem|SwapPss):' \
        /proc/"$PID"/smaps_rollup
fi

将 1234 替换为实际进程号。smaps_rollup 并非所有内核都提供,因此命令先检查文件是否可读。

  • RssAnon 较大,通常表示匿名内存占用较多,可能来自堆、运行时对象或进程数据。
  • RssFile 较大,可能包含文件映射和文件页,不能据此认定为内存泄漏。
  • VmSwap 或 SwapPss 较大,说明该进程有部分页面进入交换空间,但还需确认当前是否正在交换。
  • Pss 会按共享比例分摊共享页面,比 RSS 更适合比较多个进程的实际内存贡献。
  • 同一负载下 RSS 或 PSS 随时间持续增长,才是进程工作集持续扩大或潜在内存泄漏的线索之一。

建议在业务变慢时和恢复时对同一进程重复采样。若某个进程占用持续增长,且系统 MemAvailable 同步下降,可重点检查该进程的缓存、连接、任务队列、运行时堆和内存释放逻辑。若多个同类进程同时增长,则还要核对进程数量、并发规模及单个进程的固定工作集。

不要仅凭 RSS 最大就终止进程。它可能是核心业务进程,也可能包含较多共享页面。操作前先确认进程归属、服务启动方式、是否存在未落盘状态,以及终止后对请求和数据的影响。

检查 OOM 和服务级内存上限

内存不足时,Linux 可能触发 OOM 处理并终止一个或多个进程。可先查看当前启动周期的内核日志:

journalctl -k -b --no-pager | \
    grep -Ei 'out of memory|oom|killed process|memory cgroup'

如果系统未使用 systemd 日志,可尝试:

dmesg -T | grep -Ei 'out of memory|oom|killed process|memory cgroup'

读取 dmesg 可能需要更高权限,部分云主机也会限制普通用户查看内核日志。没有输出不代表一定没有 OOM:日志可能已轮转、权限不足,或者事件发生在上一次启动周期。使用 systemd 的系统可继续检查上一次启动记录:

journalctl -k -b -1 --no-pager | \
    grep -Ei 'out of memory|oom|killed process|memory cgroup'

重点核对 OOM 发生时间、被终止进程的名称和 PID、日志中是否出现 memory cgroup 等信息,并确认事件时间是否与响应变慢重合。单条 OOM 日志只能证明曾经发生过内存耗尽,不能单独证明当前每次慢请求都由它导致。

如果业务运行在容器或服务管理器中,宿主机内存看起来充足,也可能是业务所在控制组触及了自己的内存上限。控制组版本和挂载路径会因系统而异。对于确认位于控制组版本 2 根目录的环境,可查看:

for file in memory.current memory.max memory.events; do
    if [ -r "/sys/fs/cgroup/$file" ]; then
        echo "### $file"
        cat "/sys/fs/cgroup/$file"
    fi
done

若使用控制组版本 1,可尝试:

for file in memory.usage_in_bytes memory.limit_in_bytes memory.failcnt; do
    if [ -r "/sys/fs/cgroup/memory/$file" ]; then
        echo "### $file"
        cat "/sys/fs/cgroup/memory/$file"
    fi
done

在控制组版本 2 中,memory.current 表示当前使用量,memory.max 表示上限,显示为 max 时通常表示未设置固定上限;memory.events 中的 high、oom、oom_kill 可用于判断是否出现过限制或 OOM 事件。

上述路径不一定是所有服务或容器实际所在的控制组目录。若命令没有输出,先检查进程的控制组归属及系统挂载路径,不要据此判断没有限制:

cat /proc/1234/cgroup

将 1234 替换为业务进程 PID。若宿主机 MemAvailable 充足,但业务所在控制组的使用量接近上限,且事件计数增加,应优先核对该服务的内存上限、进程分布和工作集,而不是盲目增加宿主机交换空间。

用时间线区分相似现象

观测结果较可能的判断下一步核实
MemAvailable 下降,si 或 so 持续有值,wa 或 b 同时升高系统内存压力及交换活动可能影响响应对照请求延迟、PSI 和进程 VmSwap
Swap 已使用,但 si、so 为零,MemAvailable 稳定可能是历史换出页面,当前未必有交换瓶颈在业务慢时继续采样,不仅凭已用量下结论
宿主机内存充足,但控制组接近上限或事件计数增加服务或容器级内存限制确认进程所属控制组、限制值和事件变化
OOM 日志与响应变慢时间相近曾发生系统级或控制组级内存耗尽核对被终止进程及事件发生时的业务状态
单个进程 RSS/PSS 持续增长,其他进程变化较小该进程工作集增长、缓存变化或潜在泄漏在相同负载下连续采样 RSS、PSS 和 VmSwap
MemAvailable、交换活动、PSI 和 OOM 证据均无明显变化现有证据不足以归因于内存不要强行归因,继续按业务现象排查

时间关联是重要条件。建议在业务慢的时段连续采集系统指标,并记录对应请求延迟;再对照进程占用、控制组事件和 OOM 日志。指标只有在同一时间段共同变化,才能增强内存瓶颈判断的可信度。

先保留现场,再决定是否调整

排查期间应避免用高风险操作改变现场:

  • 不要因为 buff/cache 较大就直接清理缓存;清理后文件读取可能重新访问存储,短时间内反而增加延迟。
  • 不要只因 Swap 已使用就关闭交换空间;内存峰值时关闭交换可能更快触发 OOM。
  • 不要在业务高峰期直接终止最大内存进程;先确认服务、数据和影响范围。
  • 不要未经核实就提高或取消控制组内存上限。
  • 不要凭一次 free -h 输出就扩容或修改内核参数。

如果业务持续不可用,确需重启或停止异常进程,应先保存日志和进程信息,并确认服务启动方式、数据持久化状态、影响范围及维护窗口。操作后通过服务状态、业务健康检查和新的内存采样验证结果;若未恢复,按原启动方式回滚,避免连续叠加未经验证的调整。

最终可执行的判断标准是:只有当业务变慢与内存余量下降或服务级上限触及、交换或内存压力指标变化、进程占用异常或 OOM 事件在时间上相互印证时,才把内存列为主要瓶颈。如果证据只有 CPU 使用率不高或 Swap 已使用,尚不足以归因;应继续采集同一时间段的指标,并确认问题属于系统整体、具体进程还是控制组限制。

目录结构
全文