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

香港初创企业网站访问变慢且可用内存偏低,如何沿请求链路排查缓存与进程占用?

发布人:Minchunlin 发布时间:2026-10-03 11:20 阅读量:2

一次访问香港初创企业网站,用户的请求通常会经过域名解析、接入层或缓存、网络连接、Web 服务器、应用进程,最后才到达数据库或其他后端组件。页面变慢与“可用内存偏低”同时出现,并不等于服务器内存已经被某一个进程全部吃光:也可能是缓存未命中导致请求集中回源,也可能是交换频繁、进程排队、应用进程泄漏,甚至只是 Linux 将空闲内存用于文件缓存后的正常显示。

排查时应沿请求链路由外到内进行:先确认慢的是全部请求还是动态请求,再核对缓存命中和各阶段耗时;随后检查网络连接,接着判断 available、交换活动和 OOM 记录,最后定位具体进程及其并发配置。修复后还要用相同请求分别验证缓存命中、缓存未命中和高并发状态,不能只看一次页面是否恢复。

正文引言配图

先确认慢请求的范围

不要一开始就重启 Web 服务或清空所有缓存。先记录故障时间、受影响的 URL、访问是否间歇性失败,以及页面返回的是 502、503、504 还是正常响应但首字节很慢。

可以先对首页、一个静态资源和一个动态页面分别测试。下面的命令适用于 Linux 服务器,example.com 替换为实际域名:

curl -sS -o /dev/null -D - \
  -w 'dns=%{time_namelookup}s connect=%{time_connect}s tls=%{time_appconnect}s starttransfer=%{time_starttransfer}s total=%{time_total}s\n' \
  https://example.com/

重点看以下字段:

  • time_namelookup:域名解析耗时。
  • time_connect:建立 TCP 连接耗时。
  • time_appconnect:启用 HTTPS 时完成 TLS 握手的耗时。
  • time_starttransfer:收到首字节前的耗时,通常最能反映缓存、排队和应用处理是否变慢。
  • time_total:完整响应耗时,可能还包括传输大文件的时间。

如果静态文件很快,动态页面的 starttransfer 明显升高,问题更可能位于缓存未命中、应用进程或后端处理,而不是所有网络请求都变慢。如果所有 URL 的连接阶段都升高,应先检查网络路径和接入层。若页面偶尔出现 502 或 504,则要把进程被杀、上游超时和并发耗尽列为重点。

第一层:确认访问入口和缓存是否改变了请求量

缓存的作用不仅是减少响应时间,也能减少到达源站的请求数。当缓存突然大量失效、缓存键发生变化,或者登录 Cookie 让请求全部绕过缓存时,原本平稳的应用进程可能在短时间内同时处理大量请求,内存和交换区就会随之承压。

查看响应头和缓存状态

curl -sS -I https://example.com/
curl -sS -I https://example.com/static/app.css

重点观察:

  • Age、ETag、Cache-Control 等缓存相关响应头;
  • X-Cache、X-Cache-Status 等由接入层或 Web 服务自行增加的状态头;
  • 是否出现 Set-Cookie、私有缓存控制或禁止缓存的指令;
  • 同一个 URL 连续请求时,响应头是否发生变化。

这些响应头不是所有环境都会默认提供。没有 X-Cache-Status 不能直接认定没有缓存,需要结合接入层日志、Nginx 配置或应用日志判断。

可以连续请求同一个页面,对比第一次和后续请求的 starttransfer:

for i in $(seq 1 5); do
  curl -sS -o /dev/null \
    -w "request=$i starttransfer=%{time_starttransfer}s total=%{time_total}s\n" \
    https://example.com/
  sleep 1
done

典型判断方式如下:

观察结果更可能的含义下一步
后续请求明显变快,且出现 Age 或 HIT 状态缓存可以工作,首次请求可能回源对比缓存未命中时的源站耗时
多次请求均未命中,应用耗时同步升高缓存规则、缓存键或 Cookie 使请求持续回源检查缓存绕过条件和回源日志
缓存命中但连接阶段仍慢入口或网络连接存在问题继续检查 DNS、TCP、TLS 和路径
缓存命中很快,但动态页面仍慢慢点位于动态请求或应用进程进入进程和上游处理检查
缓存刚清理后大量请求同时变慢可能出现缓存重建和回源峰值避免全量清理,先恢复热点缓存

需要区分三类缓存占用:

  1. Web 服务的磁盘缓存可能被 Linux 文件缓存映射到内存,这部分通常具有较强的可回收性。
  2. 应用内存缓存通常直接体现为某个进程的 RSS 增长,不能简单按“系统缓存”处理。
  3. 接入层缓存命中率下降,首先增加的是源站请求量,随后才可能表现为进程数量增加、内存升高和交换频繁。

因此,不要把“可用内存下降”和“缓存一定有问题”画等号,也不要在故障高峰直接执行全量缓存清理。清理后会造成更多回源请求,可能形成缓存击穿式的瞬时压力。

检查请求是否真的排队在源站

如果使用 Nginx 作为 Web 服务或反向代理,可以在已有访问日志中查找请求耗时、上游耗时和缓存状态。若现有日志没有这些字段,可以在计划维护窗口增加临时字段。

下面是 Nginx http 配置段中的示例,属于参考配置,不应直接覆盖整份配置文件:

log_format timing
    '$remote_addr [$time_local] "$request" '
    'status=$status request_time=$request_time '
    'upstream_response_time=$upstream_response_time '
    'upstream_status=$upstream_status '
    'cache_status=$upstream_cache_status';

access_log /var/log/nginx/access_timing.log timing;

修改前应备份配置并确认日志目录权限,修改后先检查语法,再平滑加载:

sudo cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo nginx -t
sudo systemctl reload nginx

如果 nginx -t 失败,不要继续加载;恢复备份前应先确认备份文件完整,再重新测试。临时日志可能增加磁盘写入,故障确认后可以撤回该配置。

分析日志时:

  • request_time 高、upstream_response_time 也高,通常表示应用或后端处理慢;
  • request_time 高、upstream_response_time 较低,可能是响应发送、客户端连接或网络环节较慢;
  • upstream_response_time 为 -,可能是静态文件、缓存命中,或者请求尚未到达上游;
  • upstream_status 大量出现 502、503、504,应结合应用进程、连接数和 OOM 日志继续判断。

第二层:检查网络路径,但不要用 ping 代替网页测试

网络诊断的作用是确定延迟增加发生在连接入口,还是发生在服务器收到请求之后。它不能单独证明应用正常或异常。

用 ping 观察基础连通性

ping -c 10 example.com

如果平均延迟升高或出现丢包,只能说明 ICMP 探测存在异常。某些设备会降低 ICMP 响应优先级,因此中间某一跳显示丢包、但最终目标正常,并不能直接证明该跳丢弃了网页请求。

用 traceroute 或 tracepath 观察路径变化

Linux 上可以先核验工具是否安装:

command -v tracepath
command -v traceroute

可用时执行:

tracepath example.com

或者:

traceroute -n -m 12 example.com

重点观察:

  • 是否在某一段开始出现持续的延迟上升;
  • 是否存在多次测试都出现的丢包或超时;
  • 路径是否在故障前后发生变化;
  • 最终目标是否能够完成探测。

traceroute 的中间星号并不必然表示真实转发丢包,因为路由设备可能不回复探测包。最终仍应以 curl 的 connect、TLS、starttransfer 和 total 分段耗时为准。

如果 connect 和 TLS 耗时升高,而源站日志中请求量和处理时间正常,优先检查接入层和网络路径。如果连接很快,但 starttransfer 很高,网络通常不是主要瓶颈,应回到缓存、队列和应用进程。

第三层:判断“可用内存偏低”是否是真正的内存压力

Linux 中 free 很低并不一定是故障。系统会把暂时不用的内存用于文件缓存,因此应重点看 available,再结合交换输入输出和内存压力指标。

第三层:判断“可用内存偏低”是否是真正的内存压力配图

记录内存、交换和压力指标

下面的命令适用于常见 Linux 发行版:

free -h
vmstat 1 5
swapon --show
cat /proc/pressure/memory

可以看到类似这样的示例结果:

               total        used        free      shared  buff/cache   available
Mem:             4.0Gi       3.1Gi       180Mi       120Mi       760Mi       620Mi
Swap:            2.0Gi       1.1Gi       920Mi

这组数值只能作为解释机制的示例,不代表某台实际服务器的监控结果。判断时按以下顺序进行:

  1. available 持续很低,说明系统可立即分配的内存余量不足;单次采样不足以证明故障。
  2. buff/cache 较高但 available 仍充足,通常属于可回收缓存,不应直接清空。
  3. Swap 已使用不等于当前正在发生严重交换。有些页面可能早已被换出,但近期没有再次访问。
  4. vmstat 中 si 和 so 持续出现较高数值,说明内存页面正在频繁换入换出,通常会直接拉高请求延迟。
  5. /proc/pressure/memory 中 some 或 full 的 avg10、avg60 持续升高,说明进程因内存资源不足而等待。

没有统一适用于所有业务的硬阈值。作为预警参考,持续可用内存低于总内存的约 10%~20%,同时伴随交换活动或内存压力升高,就应立即检查进程和并发,而不是继续提高工作进程数。

检查是否发生 OOM

内核可能在系统或服务的内存上限耗尽时杀掉某个进程。适用于使用 systemd 的 Linux 系统的检查方式如下:

sudo journalctl -k --since "2 hours ago" | \
  grep -Ei 'out of memory|oom|killed process'

也可以查看当前启动周期内的内核信息:

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

出现类似 Killed process、Out of memory 的记录,说明已经发生过 OOM 处置。被杀的可能是应用进程,也可能是数据库或其他高占用服务。不要只根据“谁的 RSS 最大”来判断责任,还要结合被杀进程、发生时间和访问日志。

如果主机有足够 available,但某个服务仍被杀,需要检查服务或容器的内存上限。systemd 服务可以使用:

systemctl show  -p MemoryCurrent -p MemoryMax

其中 应替换为实际服务名。先用下面的命令核验服务名称,避免猜测版本化服务名:

systemctl list-units --type=service --state=running
systemctl list-unit-files | grep -Ei 'nginx|php|fpm'

若 MemoryMax 设置得较低,问题可能是 cgroup 限额,而不是整台服务器物理内存不足。此时应调整服务资源规划或降低进程并发,并保留原配置以便回滚。

第四层:定位真正占用内存的进程

确认存在内存压力后,再区分是 Web 工作进程过多、单个进程异常膨胀、应用缓存过大,还是后端服务占用过高。

先按 RSS 排序

ps -eo pid,ppid,user,comm,%mem,rss,%cpu --sort=-rss | head -n 20

rss 通常以 KiB 显示,代表进程当前驻留在物理内存中的部分;VSZ 是虚拟地址空间,不能直接当作实际占用。多个工作进程可能共享代码页,因此把每个 RSS 简单相加会有重复计算,但它仍适合用来发现异常进程。

可以持续观察进程数量和内存变化:

vmstat 1 5
ps -C nginx -o pid,ppid,comm,%mem,rss,%cpu --sort=-rss

如果系统中的 Nginx 服务名或进程名不同,应先通过 ps -ef | grep 或服务清单确认,避免使用错误名称。

重点看三种形态

一是进程数量过多。 应用单进程占用并不高,但工作进程数量快速增加,同样会耗尽内存。常见原因包括并发上限过高、请求阻塞、后端响应慢导致连接长期占用,以及缓存未命中后大量请求同时回源。

二是单个进程持续增长。 如果某个应用进程的 RSS 随时间不断上升,重启后暂时恢复,之后再次增长,可能存在内存泄漏、缓存没有淘汰策略或异常请求积压。短期可以安排受控的进程回收,长期仍需检查代码、扩展和缓存生命周期。

三是进程内存稳定但总内存不足。 这时应把所有主要服务放在一起看,包括 Web 服务、应用运行时、数据库、日志处理和监控进程。只盯着 Web 进程,可能会漏掉真正占用内存的后端组件。

如果已安装 sysstat,还可以用 pidstat 观察进程随时间的变化:

pidstat -r -u -p ALL 1 5

minflt/s、majflt/s、CPU 和进程状态需要结合 vmstat、访问日志一起看。单项指标升高不一定意味着故障,但某个进程在请求变慢时 RSS、CPU 和缺页活动同时升高,说明它很可能正在成为瓶颈。

第五层:把进程占用与应用并发联系起来

应用运行时的并发参数不能只按 CPU 核数设置,还必须考虑每个工作进程的实际内存。

以 PHP-FPM 或类似进程池为例,常见影响因素包括:

  • 最大工作进程数;
  • 每个工作进程的平均 RSS 和峰值 RSS;
  • 请求执行时间;
  • 是否存在慢查询或外部调用;
  • 是否设置了进程回收上限;
  • 进程池是否存在空闲、忙碌、排队状态。

可以用下面的估算思路规划内存:

可分配给应用进程的内存 ≈ 总内存 − 系统预留 − Web 服务 − 数据库及其他服务 − 安全余量

例如一台 4 GiB 服务器,系统和基础服务约占 700 MiB,后端服务约占 900 MiB,Web 层和监控约占 300 MiB,预留 700 MiB 后,应用进程池可使用的空间约为 1.4 GiB。若单个应用进程高峰 RSS 约 90 MiB,理论上不能简单地把 max_children 设置为 15,因为进程共享页、临时内存、请求峰值和其他服务都会产生波动。实际值应根据连续采样后的峰值 RSS 留出余量。

进程池参数的调整顺序建议如下:

  1. 先记录当前最大进程数、忙碌进程数和请求失败时间。
  2. 测量单个进程的平均及峰值 RSS,而不是只看空闲时内存。
  3. 在保留系统和后端余量的前提下,降低过高的并发上限。
  4. 观察排队是否增加;如果排队明显增加,应继续查找慢请求原因,而不是盲目把并发调回去。
  5. 对疑似泄漏的进程,可以谨慎设置请求数上限,让进程处理一定数量请求后平滑回收,但这只是缓解措施,不能替代代码排查。

修改进程池或 Web 服务配置前,先备份原文件,使用对应软件的语法检查命令,再采用平滑 reload。不要在高峰期直接 stop 服务;如果新配置导致错误,应使用备份恢复,重新通过语法检查后再 reload。具体服务名、配置路径和参数名称可能随发行版及软件版本变化,先用服务状态和进程启动参数核验,不要照搬未经确认的路径。

根据结果选择修复顺序

不同现象对应的处理优先级不同:

主要证据优先处理方向不宜立即做的事
缓存 MISS 增多,源站进程和回源耗时上升检查缓存键、Cookie 绕过条件和失效策略不要直接全量清缓存
available 低,si/so 持续升高降低进程并发、处理慢请求并恢复内存余量不要继续增加工作进程
出现 OOM 记录,某类进程被杀检查服务内存上限、单进程峰值和进程数量不要只重启被杀服务后结束排查
单个进程 RSS 持续增长检查内存泄漏和应用缓存淘汰策略不要把频繁重启当成长期修复
connect、TLS 耗时升高,源站处理正常排查接入层和网络路径不要先改应用并发
starttransfer 高且上游耗时高查应用队列、后端处理和数据库等待不要只增加缓存容量

增加 Swap 可以降低部分突发 OOM 风险,但不能把它当作性能修复。若交换活动已经频繁,继续依赖 Swap 往往会让请求延迟更加不稳定。扩充内存也应建立在进程峰值、缓存占用、并发和 OOM 记录之上,否则可能只是延后同类问题。

修复后的验证顺序

验证必须覆盖“缓存命中”和“缓存未命中”两类请求,同时保留资源监控。建议按以下顺序进行:

  1. 先测静态资源。

确认 DNS、连接和静态响应耗时恢复,排除网络或接入层仍然存在的问题。

  1. 再测缓存命中页面。

连续请求同一 URL,确认缓存状态稳定、starttransfer 降低,源站应用进程没有同步增加。

  1. 再测动态或缓存绕过页面。

使用实际业务请求验证应用进程是否仍然排队,观察 upstream_response_time、502/503/504 和进程数。

  1. 持续观察一个业务高峰周期。

至少同时记录 free -h、vmstat、Swap 活动、OOM 日志和主要进程 RSS。不要只在重启后的几分钟内判断修复成功。

  1. 比较修复前后的同口径数据。

关注首字节耗时、完整响应耗时、缓存命中率、应用进程峰值、可用内存最低点和错误率。修复成功的表现通常是:缓存命中稳定,未命中请求不会造成进程数失控,available 不再持续下探,交换输入输出恢复平稳,且没有新增 OOM 记录。

如果复测时缓存命中恢复但动态页面仍慢,瓶颈在应用处理链路;如果应用耗时恢复但所有请求连接仍慢,应继续看网络入口;如果延迟下降却出现可用内存快速减少,则要继续追踪进程 RSS 和缓存增长趋势。这样才能判断香港 Web 服务器是否真正拥有足够的内存余量,而不是依靠一次重启或一次缓存清理暂时掩盖问题。

目录结构
全文