后端 2ms,页面 7 秒:一次 CDN“帮倒忙“的排查实录

线上 H5 页面加载慢到离谱------静态资源 6 秒、API 接口 7 秒。服务器在国内,CDN 也配了,后端接口只要 2ms......慢在哪?

排查下来踩了三个坑:CDN 源站配了已下线的 IP动态接口也走了 CDN新域名 DNS 又解析到了旧 IP

三个坑的根因都一样------之前做过一次服务器缩容,机器下线了,但 CDN 源站、DNS 解析这些关联配置没同步清理,埋下了三颗"定时炸弹",直到这次部署新应用才全部引爆。


一、问题现象

部署应用后,访问 H5 页面加载非常慢。F12 看 Network:

  • 静态资源(JS/CSS):单个文件加载 6 秒+
  • API 接口(JSON):多个接口响应超过 5 秒

环境信息:

  • 应用服务器:阿里云 ECS(国内)
  • CDN:阿里云 CDN(已配置)
  • 用户位置:国内
  • 前端现状 :静态资源和 API 接口共用同一个 www 域名,全部走 CDN

二、排查过程

1. 排除后端问题(2ms,无辜躺枪)

用 curl 测一个典型 API 接口的各阶段耗时(curl 更多用法可参考 curl 实战:程序员必备的接口调试与性能排查利器):

shell 复制代码
curl -o /dev/null -s -w "\nDNS: %{time_namelookup}s\nTCP: %{time_connect}s\nTLS: %{time_appconnect}s\nTTFB: %{time_starttransfer}s\n总耗时: %{time_total}s\n" \
  'https://www.example.com/api/v1/config' \
  -H 'Content-Type: application/json' \
  --data-raw '{"id":"123","code":"test"}'
复制代码
DNS:  0.051s
TCP:  1.064s    ← TCP 连接就花了 1 秒
TLS:  1.089s
TTFB: 7.321s    ← 首字节 7 秒
总耗时: 7.322s

名词解释(看懂这几个指标,排查网络问题事半功倍):

指标 全称 含义 慢了说明什么
DNS DNS Lookup 域名解析耗时 DNS 服务器慢或解析链路长
TCP TCP Connect TCP 三次握手耗时 服务器远或网络链路差
TLS TLS Handshake SSL/TLS 握手耗时 证书链太长或未启用 TLS 1.3
TTFB Time To First Byte 从请求发出到收到第一个字节的时间 最关键指标------包含了 DNS + TCP + TLS + 服务端处理 + 网络传输
总耗时 Total Time 整个请求从发出到完成 TTFB 小但总耗时大 = 响应体太大或带宽不足

初步看 TTFB 7 秒,像是后端慢。但查了 SkyWalking 链路日志和 Nginx 日志:

log 复制代码
[request_time=0.002][upstream_time=0.002]

后端 1ms,Nginx 2ms,完全没问题。7 秒不在服务端。

2. 排除网络链路问题(9ms,也没问题)

shell 复制代码
ping www.example.com        # 9ms
sudo mtr -r -c 20 www.example.com  # 全程最高 20ms
dig www.example.com         # 解析到 kunlunaq.com(阿里云 CDN)
指标 结果 判断
ping 延迟 9ms 国内正常
mtr 全程 最高 20ms 正常
dig 解析 阿里云 CDN 节点 走了 CDN

网络链路也没问题。

3. 关键对比:走 CDN vs 直连源站(真相大白)

--resolve 绕过 CDN,直连源站 IP 做对比测试:

shell 复制代码
# 走 CDN(域名自然解析到 CDN 节点)
curl -o /dev/null -s -w "TCP: %{time_connect}s\nTTFB: %{time_starttransfer}s\n" \
  'https://www.example.com/api/v1/config' ...

# 直连源站(绕过 CDN)
curl -o /dev/null -s -w "TCP: %{time_connect}s\nTTFB: %{time_starttransfer}s\n" \
  --resolve www.example.com:443:源站IP \
  'https://www.example.com/api/v1/config' ...

API 接口对比

路径 TCP TTFB 结论
走 CDN 12ms 7 秒 CDN 回源巨慢
直连源站 48ms 165ms 源站没问题
Nginx upstream_time - 2ms 后端没问题

静态资源对比

路径 TTFB 总耗时 下载速度
走 CDN 6.2s 6.35s 72 KB/s
直连源站 0.16s 0.36s 1.2 MB/s

CDN 比直连慢了 40 倍。问题 100% 在 CDN 层。

进一步检查 CDN 缓存头:

复制代码
Content-Length: 459201         ← 没有 gzip 压缩,460KB 原文传输
Age: 0                        ← 每次都回源验证
X-Cache: HIT TCP_REFRESH_HIT  ← 缓存命中但回源验证(304),验证这一趟花了 6 秒

三、坑 1:CDN 源站配了已下线的 IP

查看阿里云 CDN 控制台的源站配置:

源站配了 6 个 IP,其中 3 个是之前缩容已下线的服务器。 CDN 回源时轮询到这些不可用 IP,连接超时后才切到正常节点,导致回源耗时 6~7 秒。

修复:删除旧 IP

在 CDN 控制台删除 3 个已下线的 IP,只保留在线的服务器。

静态资源从 6 秒降到 700ms,改善明显。但 API 仍比直连慢 8 倍:

指标 修复前 删旧 IP 后
API TTFB 7 秒 1.27 秒(直连只要 165ms)
静态资源 TTFB 6.2 秒 722ms

→ API 还是慢,因为 POST 请求也在走 CDN 绕路。


四、坑 2:动静未分离,API 请求也走了 CDN

前端的静态资源和 API 接口共用同一个 www 域名:

复制代码
nslookup www.example.com
→ www.example.com.w.kunlunaq.com  (CDN 节点)

所有 POST API 请求也先到 CDN,CDN 再回源到 ECS------多绕了一圈。CDN 本身是为静态资源加速设计的,对动态 POST 请求不但没有加速效果,反而因为回源增加了延迟。

修复:动静分离

域名 用途 是否走 CDN
www.example.com H5 页面 + 静态资源(JS/CSS/图片) ✅ 走 CDN
api.example.com 后端 API 接口 ❌ 直连源站

前端修改 API 的 base URL 指向 api.example.com,DNS 直接解析到源站 ECS IP,不经过 CDN。

同时优化了两个次要问题:

  • Nginx 配置静态资源长缓存Cache-Control: public, max-age=2592000, immutable,解决 CDN 每次回源验证的问题
  • 开启 gzip 压缩:460KB JS 压缩后约 120KB

切完域名,发布------然后,又挂了。


五、坑 3:新域名的 DNS 也解析到了旧 IP

切完 api.example.com 后,页面上所有接口直接 pending。

用 curl 一测,TCP 连接直接卡了 75 秒:

复制代码
DNS:  0.008s     ← DNS 正常
TCP:  75.054s    ← TCP 连接 75 秒!连不上
TTFB: 75.154s
总耗时: 75.154s

DNS 只要 8ms,但 TCP 75 秒------域名解析到的 IP 不对。有了之前的经验,第一时间去查 DNS:

果然,api.example.com 的 DNS 记录还指向了 3 台已下线的服务器 IP------同一个坑,第三次踩

修复:关闭旧 DNS 记录

关闭 3 条旧解析记录后恢复正常:

复制代码
DNS:  0.002s
TCP:  0.045s     ← 45ms,正常了
TTFB: 0.144s     ← 144ms,完美
总耗时: 0.144s

六、效果对比

指标 最初 修坑 1 后 修坑 2 + 3 后
API 接口 TTFB 7 秒 1.27 秒 144ms
静态资源 TTFB 6.2 秒 722ms ~200ms
页面请求数 N 个 N 个 N 个(后续 CORS 优化后减半,见第八节)
页面整体加载 10 秒+ 3~4 秒 1~2 秒

七、经验总结

三个坑,根因都是一样的:服务器缩容后,关联配置没清理干净。

在哪漏了 后果
坑 1 CDN 源站 IP 回源超时 6~7 秒
坑 2 架构层面:动静未分离 POST 请求白白绕 CDN
坑 3 DNS 解析记录 TCP 连接 75 秒

缩容后必须检查的配置清单

检查项 说明
CDN 源站 IP 删除已下线的 IP
DNS 解析记录 关闭/删除指向旧 IP 的记录
负载均衡后端 移除已下线的服务器
监控 target 清理不存在的采集目标
防火墙/安全组 清理旧 IP 的白名单规则

排查方法论

页面慢的时候,别急着怀疑后端------先用 curl -w 分段计时,再用 --resolve 绕过 CDN 对比。TCP 连接 75 秒?那一定不是后端的锅。

curl 的更多实战用法,可以参考:curl 实战:程序员必备的接口调试与性能排查利器


八、额外优化:干掉 CORS 预检请求

动静分离后,前端从 www.example.com 请求 api.example.com 的接口,触发了跨域。浏览器对每个 API 请求都先发一次 OPTIONS 预检请求(Preflight),相当于每个接口调用变成了两次请求:

预检请求本身也要走一次完整的 TCP + TLS + 后端处理,耗时和真实请求差不多------等于页面加载时间直接翻倍

修复:让浏览器缓存 CORS 策略

后端响应头加上 Access-Control-Max-Age,告诉浏览器"这个跨域策略 24 小时内有效,不用每次都问我":

java 复制代码
// Spring Boot CORS 配置
conf.setMaxAge(Duration.ofDays(1));  // 缓存 24 小时

对应的响应头:

http 复制代码
Access-Control-Max-Age: 86400

效果立竿见影------刷新页面,预检请求全部消失:

动静分离带来的"副作用":分了域名就有跨域,有跨域就有预检。记得加 Access-Control-Max-Age,否则优化了半天的 TTFB,全被预检请求吃回去了。


附:常见问题

mtr 报错 Failure to start mtr-packet: Invalid argument

需要 root 权限:

shell 复制代码
sudo mtr -r -c 20 www.example.com
相关推荐
电子科技圈2 小时前
SmartDV展示AI & HPC连接与存储IP解决方案,以解锁下一代算力芯片和节点的“速度密码”
网络·数据库·人工智能·嵌入式硬件·aigc·边缘计算
YQ_012 小时前
Ubuntu 执行 `ubuntu-drivers autoinstall` 后,Wi‑Fi 消失、外接显示器无反应的排查与修复
linux·运维·ubuntu
李李李li2 小时前
ubuntu22.04mt76x2u网卡断网
linux·运维·服务器
源远流长jerry2 小时前
VMware 虚拟机网络问题排查与解决方案
网络
cui_ruicheng2 小时前
操作系统入门(一):从冯诺依曼到进程概念
linux·运维·服务器·ubuntu
坤坤藤椒牛肉面2 小时前
linux驱动1
linux·运维·服务器
摸鱼仙人~2 小时前
LLM量化技术全景对比:AWQ、GPTQ、GGUF与FP8/INT8/INT4的抉择指南
运维·服务器
被考核重击2 小时前
计算机网络核心知识点笔记
网络·笔记·计算机网络
wanhengidc2 小时前
服务器 网络信息安全
运维·服务器·网络