一次“秒开”变成“转菊花”的线上事故

331 阅读3分钟

上周运营在群里炸锅:
“东南亚用户打开活动页要 7 秒,国内只要 1 秒,是不是 CDN 挂了?”
第一反应是 CDN 节点问题,结果 curl 一看,TLS 握手 30 ms,首包却 2.8 s——典型的 DNS 拖后腿。
最后发现是新买的 .app 域名没开 EDNS0-Client-Subnet,权威 DNS 把新加坡用户解析到美国去了。
要根治,得先把 DNS 协议从“输入网址”到“拿到 IP”整条链路拆个透。


解决方案:把一次域名解析拆成 5 张“车票”

🔍 关键决策点

  • 第 2 步没加 ECS,权威 DNS 只能按递归出口 IP(北京)返回最近节点,导致新加坡绕路。
  • 第 8 步 CNAME 链太长,每多一跳就加一次 RTT。

原理剖析:三层报文结构,一层比一层“黑盒”

层级协议字段作用常见坑
传输层UDP 53 / TCP 530-RTT vs 可靠传输截断后 fallback TCP 多一次 RTT
应用层QR、Opcode、RD、RA、RCODE控制递归/权威行为RCODE=2 SERVFAIL 时浏览器会重试 3 次
扩展层EDNS0-Client-Subnet把用户真实网段带给权威长度 > 512 字节时部分老旧防火墙直接丢包

抓包片段(tcpdump -nn -s0 -vvv port 53)

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 0x1234
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION: EDNS: version: 0, flags:; udp: 4096
;; CLIENT-SUBNET: 116.12.34.0/24/24

看到 CLIENT-SUBNET 就说明 ECS 生效,权威 DNS 能按用户真实地理位置返回最优 A 记录。


应用扩展:一条“秒开”配置模板

我们在 CDN 控制台 + 权威 DNS 做了三件事,把东南亚首包降到 300 ms:

# 1. 权威 DNS 打开 ECS 支持(以 NS1 为例)
curl -X PUT https://api.nsone.net/v1/zones/xxx.com/api \
  -d '{"edns_client_subnet":true}'

# 2. 缩短 CNAME 链
api.xxx.com 60 IN A 1.2.3.4   # 直接 A 记录,不再 CNAME 到 CDN 二级域名

# 3. 运营商递归 DNS 预热
dig @8.8.8.8 api.xxx.com      # 上线前手动触发全球递归缓存

环境适配说明

  • 国内用户走 114.114.114.114,海外走 8.8.8.8,两边 TTL 设 60 s,方便灰度回滚。
  • 老旧安卓 4.x 不支持 ECS,需要单独在边缘节点做 GeoIP fallback。

对比主流“加速”方案

方案原理延迟收益实施成本
ECS把用户子网带给权威100-300 ms改权威 DNS 配置
HTTPDNS绕过本地递归,直接 HTTP 拿结果50-200 ms客户端集成 SDK
DoH/DoT加密防劫持,复用 HTTP/2 多路复用0-50 ms升级系统解析库

最终组合:

  • 国内 App 内嵌 HTTPDNS 兜底;
  • 海外浏览器走 DoH(Cloudflare 1.1.1.1);
  • 权威 DNS 全量开 ECS。

举一反三:三个变体场景思路

  1. 灰度发布
    在权威 DNS 把 10% 流量解析到新版本 IP,TTL 设 30 s,出问题 30 秒全局回滚。

  2. 多活容灾
    利用 DNS 的 weighted 记录,主站 100 权重,灾备 0 权重;故障时一键把灾备调到 100,无需改 CDN。

  3. 防劫持
    客户端预埋一份“可信 IP 列表”,如果 DNS 返回的 A 记录不在列表里,立即切换到 DoH 重查,并上报异常。


小结

  • DNS 不是“黑魔法”,而是一张 5 跳的车票,每一跳都能量化。
  • 打开 ECS、缩短 CNAME、预热递归缓存,是跨国业务的三板斧。
  • 把 DNS 指标(解析耗时、TTL、ECS 命中率)接进 Prometheus,比“用户说慢”提前 5 分钟发现异常。