网站打开速度慢如何从DNS、服务器到网页逐层排查瓶颈
网站打开速度慢,不能仅凭“服务器响应慢”下结论。一次完整的页面访问通常要经过 DNS 解析、建立 TCP 连接、TLS 握手、Web 入口处理、应用执行、数据库查询、响应传输以及浏览器解析渲染。应先观察慢发生在哪一个阶段,再判断责任范围:DNS 时间高,优先看域名解析;连接和握手时间高,优先看网络、IP 地址或入口服务;首字节等待时间高,重点检查应用和数据库;首字节正常但页面仍迟迟可用,则要转向响应体大小、静态资源和前端渲染。
还要区分“所有访问都慢”“某个地区慢”“首次打开慢”“只有特定接口慢”以及“页面看似打开但交互很慢”。这些现象对应的原因树并不相同。下面按由外到内、由低风险到高风险的顺序排查,示例命令、日志和指标均用于说明判断方法,不代表已经在某个具体环境中执行过。
先确认慢的具体症状
统一测试条件
排查前先固定几个变量,否则不同时间、不同网络和不同页面之间的结果无法直接比较。
建议记录以下信息:
- 访问的完整 URL、HTTP 方法和是否需要登录。
- 测试时间、所在地区、运营商或出口网络。
- 首次访问与连续刷新后的结果。
- 使用 IPv4 还是 IPv6。
- 是否经过 CDN、负载均衡、WAF 或反向代理。
- 慢的是首页、静态资源,还是某个接口。
- 浏览器中是否出现 4xx、5xx、超时或资源加载失败。
同一个页面至少进行三次轻量测试,并保留每次的分阶段耗时。不要在故障期间反复刷新动态接口,以免把排查行为变成额外负载。
在 Linux、macOS 或安装了 curl 的环境中,可以使用下面的只读请求观察基础耗时:
curl -sS -o /dev/null \
-w 'http_code=%{http_code}\nremote_ip=%{remote_ip}\nnamelookup=%{time_namelookup}s\nconnect=%{time_connect}s\nappconnect=%{time_appconnect}s\npretransfer=%{time_pretransfer}s\nstarttransfer=%{time_starttransfer}s\ntotal=%{time_total}s\nsize_download=%{size_download}B\n' \
--connect-timeout 10 \
--max-time 30 \
'https://www.example.com/'
这些字段可以这样理解:
| 字段 | 主要反映 | 常见判断方向 |
|---|---|---|
namelookup | DNS 解析耗时 | 域名服务器、递归解析器、A/AAAA 记录 |
connect | TCP 建连完成时间 | 网络往返、端口可达性、入口服务连接队列 |
appconnect | TLS 握手完成时间 | 证书链、加密协商、网络抖动、TLS 终止设备 |
starttransfer | 收到首字节的时间 | 连接建立后等待 Web 服务、应用、数据库返回 |
total | 整个响应完成时间 | 首字节等待加下载和传输时间 |
size_download | 实际下载字节数 | HTML、接口响应或静态文件体积 |
例如,namelookup=0.02s、connect=0.05s、starttransfer=2.80s,通常不是 DNS 或 TCP 建连慢,而是 Web 入口等待后端处理。若 starttransfer=0.15s,但 total=8.00s,则要重点检查响应体大小、带宽、丢包、压缩以及浏览器后续资源。
curl 的一次结果不能代表所有用户。还应使用浏览器开发者工具的 Network 面板观察请求瀑布图,关注请求排队、DNS、Initial connection、SSL、Waiting for server response、Content Download 等阶段。浏览器显示的页面可用时间还会受到 JavaScript 执行、字体加载、图片解码和第三方资源影响,因此它可能明显晚于 HTML 请求完成时间。
区分首次访问和重复访问
首次打开慢、刷新后明显变快,常见原因包括:
- DNS、TLS 或浏览器连接尚未复用。
- CDN 或应用缓存首次未命中。
- PHP、Java、Node.js 等应用进程刚启动。
- 数据库缓存、文件系统缓存尚未热起来。
- 浏览器首次下载了字体、脚本和图片。
如果连续访问都慢,才更应该关注持续性的网络、服务器、应用或数据库问题。测试时应分别记录“冷访问”和“热访问”,不要把两种结果混为一个平均值。
先看影响范围
影响范围是建立原因树的重要线索。
| 现象范围 | 优先怀疑方向 | 下一步 |
|---|---|---|
| 所有域名和接口都慢 | 主机资源、出口网络、入口服务 | 检查系统负载、连接数和链路 |
| 只有一个域名慢 | DNS、虚拟主机配置、该站点应用 | 比较解析结果和站点日志 |
| 只有一个地区或运营商慢 | DNS 调度、路由、某个边缘节点 | 从多地区测试 A/AAAA、连接和 TTFB |
| 只有首次访问慢 | DNS、TLS、缓存、冷启动 | 对比首次和重复访问 |
| 只有动态接口慢 | 应用、数据库、外部依赖 | 看接口级日志和上游等待 |
| 静态文件慢,接口正常 | 文件体积、CDN、网络传输 | 看缓存命中、压缩和下载阶段 |
| 网络请求很快但页面迟迟可用 | JavaScript、渲染、第三方资源 | 看 Performance 和长任务 |
建立“网站变慢”的原因树
可以把一次请求拆成五层:

- 名称解析层:域名是否快速、稳定地解析到正确地址。
- 链路与接入层:客户端到 CDN、负载均衡或服务器的连接是否稳定。
- Web 入口层:Nginx、Apache、网关或负载均衡是否在排队。
- 应用与数据库层:业务代码、缓存、数据库和外部依赖是否耗时。
- 资源与浏览器层:响应体、图片、脚本和页面渲染是否拖慢可用时间。
排查时不要在每层都直接改配置。先通过耗时拆分、日志和相关指标确定分支,再做单项验证。一个适合快速定位的判断顺序如下:
- DNS 时间高:先查解析,不要先重启服务器。
- TCP 或 TLS 时间高:先查链路、IPv4/IPv6、入口 IP 和连接队列。
- TTFB 高而下载短:先查 Web 入口、应用、缓存和数据库。
- TTFB 正常而下载长:先查响应大小、压缩、带宽和丢包。
- 网络请求完成但页面慢:先查前端脚本、图片、字体和第三方调用。
第一层:排查 DNS 解析
DNS 慢不等于服务器慢
DNS 解析通常会被递归解析器、操作系统或浏览器缓存。解析慢可能只影响首次访问,但如果权威 DNS 响应超时、记录配置不完整或某个解析地址不可达,用户仍可能频繁遇到等待。
可以先查询域名的基本记录:
dig www.example.com A
dig www.example.com AAAA
dig www.example.com CNAME
关注以下内容:
- 是否存在意外的 CNAME 多级跳转。
- A 记录和 AAAA 记录是否都指向可用入口。
- 返回了多少个 IP,是否存在某一个异常地址。
Query time是否明显高于其他时间。- TTL 是否过短,导致递归解析器频繁回源。
- 是否出现
SERVFAIL、REFUSED或超时。
下面是格式示例,数值仅用于演示:
;; ANSWER SECTION:
www.example.com. 300 IN A 203.0.113.20
;; Query time: 18 msec
;; SERVER: 192.0.2.53#53
一次查询耗时 18 毫秒并不能证明所有用户都正常,也不能仅凭一次 800 毫秒的查询就判定权威 DNS 故障。应从不同网络、不同递归解析器重复观察,并对比本地 DNS 与权威 DNS 的结果。
重点检查 A、AAAA 和解析调度
如果域名同时配置 A 和 AAAA,而 IPv6 路径、IPv6 入口或防火墙配置不完整,部分客户端可能优先尝试 IPv6,等待失败后再回退 IPv4,表现为“有些用户打开很慢”。

可以分别比较两种协议:
curl -4 -sS -o /dev/null \
-w 'IPv4 total=%{time_total}s connect=%{time_connect}s starttransfer=%{time_starttransfer}s\n' \
--max-time 20 \
'https://www.example.com/'
curl -6 -sS -o /dev/null \
-w 'IPv6 total=%{time_total}s connect=%{time_connect}s starttransfer=%{time_starttransfer}s\n' \
--max-time 20 \
'https://www.example.com/'
如果 IPv4 稳定而 IPv6 经常超时,问题范围通常落在 IPv6 路径、AAAA 指向、监听地址或访问控制,而不是应用代码。是否调整 AAAA 记录,应先确认所有 IPv6 入口和回源链路,避免只改 DNS 隐藏真实故障。修改 DNS 前要记录原记录和 TTL,变更后根据 TTL 和递归缓存情况等待传播,并准备恢复原记录的回滚方案。
如果使用 CDN 或 DNS 调度服务,还应比较不同地区返回的 IP。某一地区持续返回异常地址,可能是调度策略、边缘节点健康检查或区域链路问题。此时不要直接把解析结果中的 IP 当作源站 IP,也不要绕过既有安全设备进行未经授权的回源测试。
第二层:排查网络、连接和 TLS
连接慢要拆成网络慢与入口排队
当 DNS 已经很快,但 connect 或 appconnect 明显升高,可能原因包括:
- 客户端到入口 IP 的网络延迟或丢包。
- 某个运营商到目标机房的路由异常。
- IPv4 和 IPv6 路径质量差异。
- TCP 连接队列、文件描述符或连接跟踪表接近上限。
- TLS 握手协商、证书链或加密设备处理缓慢。
- 防火墙、WAF、负载均衡器正在丢包或限流。
可以从客户端观察路径,但不能把中间路由器不响应 ICMP 直接视为网站丢包:
ping -c 20 www.example.com
mtr -rwzbc 20 www.example.com
ping 只能反映 ICMP 的响应情况,不等价于 HTTPS 请求结果。mtr 中某一跳显示丢包,而后续跳和最终目标正常,常常只是该中间设备限制了 ICMP。只有从某一跳开始,后续各跳和最终目标都持续出现相近比例的丢包,才更值得结合 TCP 或 HTTPS 测试继续判断。
如果条件允许,可以用 curl 直接重复请求同一个域名,并记录返回的 remote_ip。不同次请求命中不同 IP 时,应按 IP 汇总耗时,而不是只看总体平均值。对某个已知入口 IP 做验证时,优先使用 --resolve 保留域名和 TLS SNI:
curl --resolve www.example.com:443:203.0.113.20 \
-sS -o /dev/null \
-w 'ip=%{remote_ip} code=%{http_code} connect=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n' \
--max-time 20 \
'https://www.example.com/'
这里的 203.0.113.20 只是文档示例地址。实际测试只能使用已经确认属于本业务、且允许测试的入口 IP。不能随意把域名解析到陌生地址,也不能将直接访问源站的结果与经过 CDN 的结果混为一谈。
从服务器侧看连接状态
在 Linux 主机上,可以使用以下只读命令查看连接和网卡统计:
ss -s
ss -lnt
ip -s link
重点关注:
- TCP 总连接数是否突然升高。
- 监听端口是否存在大量
SYN-RECV,提示握手队列或攻击流量压力。 TIME-WAIT数量是否异常,但不能仅凭数量判定故障。- 网卡是否出现明显丢包、错误或丢弃。
- 监听服务是否只绑定了 IPv4 或只绑定了 IPv6。
若使用 systemd 管理服务,可查看服务状态和近期日志:
systemctl status nginx --no-pager
journalctl -u nginx --since "15 minutes ago" --no-pager
服务名可能是 apache2、httpd 或其他自定义名称,先用实际部署方式核对,不要直接套用命令。若发现端口监听正常但外部连接仍慢,应继续对比主机内网测试、入口设备日志和外部多地点测试。
第三层:排查 Web 入口和反向代理
用请求时间字段区分入口与上游
Nginx、Apache、网关或负载均衡器通常能记录请求总时长和上游耗时。以 Nginx 为例,常见的诊断字段包括:
$request_time:从接收请求到完成响应的总时间。$upstream_connect_time:连接上游应用的时间。$upstream_header_time:连接上游后等待上游响应头的时间。$upstream_response_time:从连接上游到接收完上游响应的时间。
示例日志格式如下,字段布局仅作说明:
2025-03-08T10:20:31+08:00 request_time=2.418 upstream_connect_time=0.004 upstream_header_time=2.391 upstream_response_time=2.402 status=200 request="GET /api/orders HTTP/1.1"
2025-03-08T10:20:32+08:00 request_time=0.082 upstream_connect_time=- upstream_header_time=- upstream_response_time=- status=200 request="GET /assets/app.css HTTP/1.1"
第一行表示 Nginx 很快连上应用,但等待上游响应头接近 2.4 秒,优先检查应用和数据库。第二行没有上游字段,可能是静态文件由 Nginx 直接返回,耗时仅 82 毫秒。
如果 request_time 高,而 upstream_response_time 很低,可能是响应体传输慢、客户端读取慢、代理缓冲或网络链路问题。如果两者都高,则继续向应用层追踪。若大量请求返回 499,常见含义是客户端在服务端完成响应前主动断开,但仍需结合客户端超时设置和后端耗时判断,不能直接认定为服务器故障。
检查入口服务的排队和缓存
Web 入口层常见瓶颈包括:
- worker 进程或线程不足。
- 上游连接池耗尽。
- keepalive、代理缓冲或超时配置不合适。
- 静态文件未命中缓存,每次都回源。
- CDN 缓存未命中,源站承受大量重复请求。
- TLS 终止设备、WAF 或负载均衡器资源不足。
- 某个接口突发流量拖慢了同一入口上的其他请求。
可以将同一 URL 分别测试缓存命中和未命中情况,观察响应头中的 Age、缓存状态、自定义上游标记以及 Cache-Control。不要只看 HTTP 状态码为 200 就认为请求健康,200 响应也可能等待了几秒。
如果要调整 Nginx、网关或负载均衡配置,应先备份当前配置,确认变更只影响目标站点或目标 upstream,使用配置校验命令后再平滑加载,并保留原配置作为回滚版本。例如 Nginx 配置变更前后应遵循:
sudo cp -a /etc/nginx /etc/nginx.backup-$(date +%Y%m%d%H%M%S)
sudo nginx -t
只有在 nginx -t 通过且确认影响范围后,才考虑按现有运维流程 reload。不要在没有备份、没有变更窗口或没有回滚路径时直接修改连接数、超时、缓存和 worker 参数。参数变大不一定更快,也可能把压力继续传给应用和数据库。
第四层:排查应用服务
用 TTFB 和接口维度定位代码等待
如果 DNS、TCP 和 TLS 都正常,而 starttransfer 较高,重点就从网络转向 Web 入口之后。应用慢的常见原因包括:
- 某个 SQL 查询耗时增加。
- 等待数据库连接池、线程池或任务队列。
- 调用支付、消息、搜索等外部服务超时。
- 缓存未命中或缓存服务响应慢。
- 大量锁竞争、垃圾回收或单线程事件循环阻塞。
- 近期发布引入了低效循环、重复查询或大对象序列化。
- 某个接口被突发请求放大,拖慢共享进程。
不要只看整站平均 TTFB,应按路径、方法、状态码、版本和请求来源分组。例如首页可能只有 100 毫秒,而 /api/report 达到 4 秒;两者的排查方向完全不同。
建议为一次请求保留可关联的请求 ID,并在入口日志、应用日志和数据库调用日志中传递。一个完整的应用日志应至少能回答:
- 请求进入应用的时间。
- 排队等待了多久。
- 业务代码执行了多久。
- 数据库调用次数及总耗时。
- 外部 HTTP/RPC 调用次数及耗时。
- 序列化、模板渲染和响应写出的耗时。
- 最终状态码和响应大小。
示例应用日志可以这样理解:
request_id=7f31 route=/api/report queue=0.012s db=2.184s external=0.006s render=0.031s total=2.247s status=200
request_id=8a42 route=/api/report queue=1.806s db=0.041s external=0.004s render=0.012s total=1.869s status=200
第一条更像数据库查询慢,第二条数据库本身很快,但请求在应用队列中等待,可能是线程池、进程数或并发控制出现瓶颈。只有 total 而没有分段数据时,不要直接猜测具体代码位置,应先补充观测。
关注超时和错误,不要只看成功请求
大量 200 并不代表没有性能问题。应用可能在接近超时前返回 200,用户仍然感觉页面迟缓。相反,少量 500 可能是慢查询、连接池耗尽或外部依赖超时的结果。
应同时查看:
- 2xx、3xx、4xx、5xx 的比例变化。
- 连接池使用率和等待时间。
- 线程池、协程池或消息队列积压。
- 外部依赖的超时、重试和熔断次数。
- GC 暂停、事件循环延迟或进程重启。
- 发布前后同一路由的 p50、p95、p99 延迟。
平均值容易掩盖尾部请求。假设 95% 请求在 200 毫秒内完成,但 5% 请求等待 8 秒,用户仍可能频繁遇到明显卡顿。排查时应优先看 p95 和 p99,并把慢请求样本与时间点对应到日志,而不是只看全天平均值。
第五层:排查数据库和缓存
数据库慢通常表现为 TTFB 高
当应用日志显示数据库调用占据大部分请求时间,应进一步区分查询执行慢、等待连接慢和锁等待慢。
常见表现如下:
| 观察结果 | 更可能的原因 | 继续检查 |
|---|---|---|
| 单条查询执行时间持续升高 | 索引、扫描行数、数据量、执行计划 | 慢查询日志和执行计划 |
| 查询本身很快,但应用等待连接 | 连接池过小、连接未释放、数据库连接上限 | 应用池等待和数据库连接数 |
| 某些时间段突然大量等待 | 锁竞争、批处理、长事务 | 活跃事务和锁等待 |
| 读请求变慢且磁盘繁忙 | 缓存未命中、内存不足、随机 I/O | Buffer 命中、磁盘延迟 |
| 只有报表或导出接口慢 | 大范围扫描、排序、聚合 | 查询范围、分页和异步化 |
生产环境查询诊断应使用只读账号和低影响方式。查看活动连接、慢查询统计通常风险较低,但仍可能增加监控开销;对复杂语句执行 EXPLAIN 前要确认数据库版本和语句类型,不能在生产环境随意执行会真正运行查询的分析命令。涉及索引、表结构、参数或事务设置的变更,应先备份或保留可恢复方案,在测试或低峰环境验证后再发布。
不要用“数据库 CPU 不高”排除数据库问题。锁等待、磁盘延迟、连接池等待和网络阻塞都可能在 CPU 较低时发生。还要检查应用是否存在 N+1 查询:一个页面请求先查询列表,再为每条记录分别查询详情,数据量增大后延迟会按记录数放大。
缓存命中不能替代数据一致性判断
缓存可能让首页很快,但动态接口仍然慢;也可能缓存失效后,大量请求同时回源,形成缓存击穿。应观察:
- 缓存命中率和未命中率。
- 缓存键是否包含不必要的用户或时间参数。
- 未命中时的回源耗时。
- 热点数据是否在同一时间集中失效。
- 缓存服务连接数、内存和淘汰次数。
- 数据更新后是否出现旧数据或缓存雪崩。
不要为了追求速度盲目延长所有缓存时间。缓存策略需要与数据时效、权限隔离和失效机制一起验证。若变更缓存规则,先记录原有 TTL、键规则和失效方式,确保出现数据错误时可以恢复。
第六层:排查服务器资源和系统限制
应用和数据库之外,主机本身可能受到 CPU、内存、磁盘、网络或系统限制。Linux 上可以先执行以下只读检查:
uptime
free -h
vmstat 1 5
df -h
df -i
ss -s
如果系统安装了 sysstat,还可以使用:
iostat -xz 1 5
pidstat -u -r -d 1 5
判断时不要只看单一指标:
- CPU 使用率高:检查是 Web 进程、数据库、压缩、加密还是其他任务消耗。
- CPU 使用率不高但 load average 高:可能存在磁盘 I/O 等待、不可中断睡眠或锁竞争。
- 内存使用接近上限且 swap 活跃:应用可能因换页产生明显延迟。
- 磁盘利用率高、await 增大:数据库、日志写入或文件读取可能被拖慢。
- 磁盘空间或 inode 用尽:日志、临时文件和应用写入可能失败。
- 网卡错误、丢弃增加:需要检查虚拟网卡、宿主机、带宽和上游设备。
- 文件描述符接近上限:新连接、日志或文件读取可能失败。
- 容器受到 CPU 或内存配额限制:宿主机空闲不代表容器有足够资源。
load average 是等待运行或等待资源的任务数量概览,不是 CPU 百分比。虚拟机中的 CPU steal、容器 cgroup 限制和宿主机 I/O 争用,也可能使应用延迟上升而主机总体指标看起来正常。
如果运行在容器中,应同时查看容器层面的 CPU、内存、重启次数和限制值。不要在故障期间直接提高容器配额或关闭 swap 来“试试效果”,这类改动可能扩大影响范围。先保留当前配置和监控数据,确认瓶颈后再进行可回滚的资源调整。
第七层:确认是不是网页本身慢
TTFB 正常不代表页面已经可用
当 HTML 很快返回,但用户仍然要等待数秒,问题往往位于浏览器侧:
- 首屏图片过大或未使用合适格式。
- JavaScript 文件体积大、执行时间长。
- 脚本阻塞 HTML 解析。
- 第三方统计、广告、客服或地图资源超时。
- 字体加载阻塞文本显示。
- 页面发起了大量串行接口请求。
- DOM 节点过多,布局和样式计算耗时。
- 图片、视频没有按需加载。
在浏览器 Network 面板中,先查看文档请求是否已经快速完成,再看后续资源。一个常见判断是:

- 文档 TTFB 高:继续查服务器、应用和数据库。
- 文档 TTFB 低,但
Content Download长:检查响应体大小、压缩和链路。 - 资源请求完成,但页面仍卡顿:切到 Performance 面板看脚本执行、长任务和布局。
- 某个第三方域名长期 pending:临时阻断或替换该资源进行对比,不要直接把第三方延迟归咎于源站。
浏览器中的 LCP、FCP、INP 等指标描述的是用户实际看到页面和进行交互的体验,不等同于服务器 TTFB。服务器可以在 100 毫秒内返回 HTML,但如果首屏脚本要执行 2 秒,用户仍会感觉打开慢。
检查响应大小和压缩
可以用 curl 查看响应头和大小:
curl -sS -D - -o /dev/null \
-H 'Accept-Encoding: gzip, br' \
'https://www.example.com/assets/app.js'
关注 Content-Encoding、Content-Length、缓存头和内容类型。压缩是否有效,需要结合文件类型和客户端支持情况判断。已经压缩过的图片、视频和部分归档文件再次压缩收益通常有限,反而会增加 CPU 消耗。
不要把所有静态资源都合并成一个超大文件,也不要只追求减少请求数而忽略缓存更新、按需加载和首屏优先级。更合理的验证方式是先找出体积最大、阻塞最长或重复下载的资源,再进行单项优化,并用浏览器瀑布图和真实用户数据确认变化。
一套由外到内的排查流程
当网站正在变慢时,可以按以下顺序执行,避免一开始就重启服务或修改配置。
1. 建立基线
记录三个时间点:
- 正常时的 DNS、连接、TLS、TTFB 和总耗时。
- 当前故障时的同一组指标。
- 恢复后的同一组指标。
同时记录测试地点、协议、入口 IP、URL 和 HTTP 状态码。没有基线时,所谓“变快”可能只是换了缓存或换了测试网络。
2. 先做外部对比
从至少两个网络环境请求同一个 URL,比较:
- DNS 返回是否一致。
- 是否命中不同 IP。
- IPv4 与 IPv6 是否有明显差异。
connect、TLS 和 TTFB 哪一段变慢。- 静态资源和动态接口是否表现一致。
如果只有一个地区慢,优先看 DNS 调度、区域路由和边缘节点;如果所有地区同时慢,再转向入口、应用、数据库和主机资源。
3. 再做服务器侧时间对齐
用客户端请求时间、Web 访问日志和应用日志进行对齐。重点不是寻找一条“看起来最慢”的日志,而是确认同一个请求在各层花了多少时间:

- 客户端到入口:由 curl 或浏览器时间反映。
- 入口等待上游:由 Nginx 或网关字段反映。
- 应用处理:由请求 ID 和应用分段日志反映。
- 数据库调用:由慢查询和应用数据库耗时反映。
- 响应传输:由入口总时长、响应大小和客户端下载时间反映。
4. 一次只验证一个假设
例如怀疑数据库慢,不要同时升级主机、清缓存、改连接池和重启应用。可以先选一条慢请求,检查其数据库耗时;确认后再在低风险条件下验证索引、查询范围或连接池设置。
如果需要改变配置,应遵循“备份当前值—小范围变更—观察—保留回滚”的顺序。涉及 DNS、缓存和 CDN 的变化,还要考虑缓存 TTL 和传播时间,不能在几分钟内连续多次改动后凭结果判断某一次变更有效。
如何确认已经定位到根因
定位根因至少要满足“现象、证据、修复后变化”三者一致。
例如:
- 现象是部分地区首次访问延迟高;证据是这些地区解析到某个不可用或高延迟地址;修复后同一地区的 DNS 和连接耗时同步下降。
- 现象是动态接口 TTFB 高;证据是入口很快连接应用,但应用日志显示数据库查询占据大部分时间;优化查询或恢复索引后,数据库耗时和 TTFB 同时下降。
- 现象是接口正常但页面晚出现;证据是 HTML 返回很快,某个脚本执行时间长;延迟加载或拆分脚本后,前端交互指标改善。
- 现象是连接阶段随机超时;证据是某个入口 IP 的 TCP 重传和连接失败率明显高于其他入口;摘除该入口后错误率恢复正常。
只有重启服务后暂时恢复,不能证明根因是“服务需要重启”。重启可能清空连接池、释放内存、结束锁等待或刷新缓存,但也会丢失现场。恢复后应继续查看重启前的日志、资源曲线和连接状态,避免下次故障再次依赖重启。
验证恢复时应使用与故障期间相同的 URL、网络、协议和测试方法,并持续观察一段时间。动态问题需要覆盖业务高峰或相同并发条件,否则短时间正常不代表根因已经消失。
常见误判与边界
Ping 很高不等于网页一定慢
ICMP 可能被限速或丢弃,HTTPS 请求却正常。判断网站速度应优先看 TCP、TLS 和 HTTP 分阶段耗时。反过来,ping 正常也不能排除应用等待和数据库慢。
CPU 不高不等于服务器没有瓶颈
锁等待、磁盘 I/O、线程池排队、连接池耗尽和外部依赖超时,都可能在 CPU 较低时发生。必须把 CPU、内存、I/O、连接和应用分段耗时放在一起看。
HTTP 200 不等于用户体验良好
请求可能等待了 5 秒后才返回 200。应同时观察 p95、p99、超时、取消请求和前端可用时间。
CDN 命中不等于源站健康
静态资源可能由 CDN 正常返回,但动态接口仍然回源失败;也可能 CDN 缓存掩盖了源站变慢。排查时要区分边缘响应、回源响应和源站直接处理时间。
直接访问 IP 不能简单替代域名访问
HTTPS 依赖 Host 和 SNI,负载均衡还可能按域名选择后端。用 IP URL 测试可能命中错误站点或证书,优先使用保留域名的 --resolve,并确保 IP 属于授权测试范围。
恢复后应保留的监控点
一次故障解决后,至少应留下能够再次回答“哪一层先变慢”的监控数据,而不只是一个总响应时间。
| 层级 | 建议监控点 | 发现异常时的方向 |
|---|---|---|
| DNS | 解析耗时、失败率、SERVFAIL、A/AAAA 返回差异 | 权威 DNS、递归解析、记录和调度 |
| 网络 | TCP 建连、TLS 握手、重传、连接失败率 | 路由、入口 IP、IPv4/IPv6、边缘节点 |
| Web 入口 | 请求总耗时、上游耗时、499、5xx、缓存命中 | 代理、负载均衡、缓存和上游连接 |
| 应用 | p50/p95/p99、线程池、队列、外部依赖 | 代码、连接池、重试和超时 |
| 数据库 | 慢查询、锁等待、连接数、磁盘延迟 | SQL、索引、事务和资源 |
| 主机 | CPU、内存、swap、I/O、文件描述符、网络错误 | 虚拟机、容器、系统限制 |
| 前端 | LCP、INP、资源体积、长任务、第三方失败 | 脚本、图片、字体和渲染 |
监控阈值不宜脱离自身基线。可以先用一段稳定时期建立正常范围,再对“相对基线明显升高”设置告警。例如入口 TTFB、应用 p95、数据库锁等待和 5xx 率同时升高时,告警应附带请求路径和时间窗口,方便直接关联日志。
最终目标不是记住某个固定耗时标准,而是让每次慢请求都能沿着 DNS、网络、Web 入口、应用、数据库和网页资源逐层缩小范围。只有把影响范围、分阶段耗时和服务端日志对齐,才能区分“服务器真的慢”“网络到不了”“DNS 返回异常”以及“服务器已经返回,但浏览器还没有把页面呈现出来”。



