Skip to content

ECS 就近调度 ​

ECS(EDNS Client Subnet)让递归在问权威时附上设备所在的网段,CDN 据此返回离设备最近的节点。

为什么这是必需品 ​

境外 CDN 的权威在境外,查询必然走隧道。如果那台权威收不到设备的子网,它只能按隧道出口(香港)判断你在哪,于是把国内设备整体调度到香港节点:链路通、解析成功,但绕了一大圈。

所以对这套分流架构来说,ECS 不是优化项,而是让「走隧道问境外权威」不付出就近代价的前提。

发给谁:白名单按「这台权威服务谁」收敛 ​

Unbound 只向白名单里的权威发送 ECS(/etc/unbound/unbound.conf.d/dns-stack-ecs.conf,由流水线每 15 分钟重建并热重载,缓存保留)。收录规则:

  • 国内权威(@cn_authority)一律收录。
  • 只要 CDN 直连规则集证明某家 CDN 在大陆有节点,它的境外权威也收录,不必等人工往表里补。
  • 境外权威只进白名单,永不进直连集合:直连问境外权威会吃污染。

不按「权威 IP 在不在大陆」收:一个大站四台权威三台在境外,轮询到那三台就不发 ECS,结果时好时坏地被调度到香港。

判据由两层组成:

层来源回答的问题
internal/cdn 静态后缀表人工维护这个域名属于哪家 CDN、是不是按地理调度
cdn-direct.txt 规则集本仓库的 Action 每日重建这家 CDN 在大陆到底有没有节点段

规则集从各家官方前缀源与 ASN 通告拉取,按 APNIC 大陆基线切成大陆段与境外段。不引用任何第三方规则源:它直接决定 ECS 发给谁,口径和存续必须受控。

按片缓存 ​

带 ECS 的答案不能被所有设备共用,否则北京电信拿到的节点会被上海联通复用。mosproxy 按 ECS 分片表把设备地址归到「省份 + 运营商」分片,答案按分片缓存。分片表由流水线生成。

Unbound 侧开着 client-subnet-always-forward: yes:带 ECS 的查询不去读全局缓存。否则 prefetch 和本机自查(都不带 ECS)拿到的境外节点会盖住按子网查到的大陆节点——2026-09-22 实测,本来能拿到大陆节点的域名里 24% 被这样打成了境外,改成 yes 后为 0%。

验收:cdn-hit ​

bash
dns-stack cdn-hit           # 以真实中国 /24 的身份解析国内外大厂域名
dns-stack cdn-hit --fresh   # 先清掉这批域名连同整条 CNAME 链的缓存,再测

它重点报出「这家 CDN 在大陆有节点、答案却落在境外」——那不是分流出了问题,是 ECS 没送达那台权威。

判定「是不是大陆节点」用的是 direct4,而不是规则集里的归属。国产 CDN 把节点放在运营商机房、用的是运营商的 IP,那些段不由 CDN 自己的 ASN 宣告,按 ASN 去查永远查不到。

为什么需要 --fresh ​

scope=0 的答案会被 Unbound 缓存成全局条目,之后任何子网的查询都命中它且不回显 scope。于是「无回显」既可能是没送达,也可能只是命中了缓存——判不出。

--fresh 在探测前把这批域名连同 CNAME 链逐个清掉(只清查询名不够,链末端的 A 记录还在缓存里),强制走一次真实递归。此时仍然无回显就只剩一个解释:子网没送到那台权威。

面板「工具 → CDN 就近」一次测完电信、联通、移动三个网段,结果排成「网站 × 运营商」的表格;「复核」按钮对应 --fresh。代价是这些热门域名下一次解析要走完整递归,所以 10 分钟内只允许一次。

看自己实际拿到什么 ​

服务器上的自查不带 ECS,看到的是默认节点。要看某个运营商的设备实际会拿到什么,带上网段:

bash
dns-stack test www.example.com 219.141.136.0/24   # 电信
dns-stack test www.example.com 123.125.0.0/24     # 联通

最终以设备自己的视角为准:面板「工具 → 我的位置」在浏览器里发起探测,代表的才是设备的真实体验。

只有两台机器:一台国内,一台香港。