说说 GeoDNS 和 Anycast 那些事
posts/understanding-geodns-and-anycast为什么在不同的网络地区下载同一个文件,下载速度都很快?很多人第一反应是 CDN 缓存,这没什么问题。但除此之外请求其实还经历了多层调度:DNS 层的 GeoDNS 负责选择区域入口,然后网络层的 Anycast 负责选择接入节点,最后应用层的负载均衡再负责把流量分配到具体机器。下面来说说前两层是怎么工作的。
GeoDNS 和 Anycast
想要理解 CDN 的流量调度,需要分清 GeoDNS 和 Anycast 这两个概念。
GeoDNS 是在 DNS 层面工作的。当用户查询一个域名时,权威 DNS 服务器会根据查询来源 IP 的地理位置,返回不同的解析结果。比如在国内的请求返回一组国内 IP,美国的请求返回一组美国 IP。它的特点是粗粒度、策略明确,但也受制于 DNS 缓存和 Resolver 位置的限制。
Anycast 则是在网络路由层工作的。同一个 IP 地址在全球多个节点同时广播,用户请求到达运营商路由器后,BGP 协议会根据路由策略(如 AS Path、Local Preference 等)选择一条最优路径,把流量导向某个接入节点。这条路径通常接近用户,但它优化的是路由策略,而不是严格意义上的物理距离或网络延迟。
打个比方:GeoDNS 像是给你一张指定城市的门票,你只能去那个城市;Anycast 像是全国连锁门店都用同一个门牌号,但你从家出发时,BGP 会按运营商的策略把你导航到某一家,大部分情况下是近的,但偶尔也可能绕远。
在现代 CDN 架构里,就近接入核心靠的是 Anycast,GeoDNS 更多是粗粒度的入口选择,甚至有些纯 Anycast 架构里,DNS 永远只返回同一个 IP,所有调度完全交给网络层完成。
一次真实请求是怎么被调度的
如果把一次典型的 CDN 请求拆开来看,完整的链路大概是:
用户请求
-> 本地 DNS Resolver
-> GeoDNS(Region 级别,返回一个候选 IP 池)
-> Anycast/BGP(POP 级别,选择具体接入节点)
-> 边缘负载均衡(机器级别,选择具体实例)
-> 缓存节点 / 回源
GeoDNS 只参与 DNS 阶段的入口选择,而且通常是在 Region 级别做决策(比如华北、北美、欧洲)。后续真正决定你进哪个具体接入点(POP)的,是 Anycast 路由;而最终落到哪台机器,则由边缘负载均衡决定。
DNS 是怎么知道我在哪的
这里要分清楚一个概念:权威 DNS 服务器本身并不知道你的物理位置。它能做的,只是看着你发过来的 DNS 查询包的源 IP 地址,然后去翻一本字典,这本字典就是 GeoIP 数据库。
GeoIP 数据库是一张巨大的对照表,把全球的 IP 地址段映射到对应的地理位置信息(国家、省份、城市、经纬度、ASN 运营商等)。市面上最常见的厂商包括 MaxMind(GeoIP2)、IP2Location、DB-IP 等。
当权威 DNS 收到查询请求时,它的逻辑大致如下:
- 提取源 IP:从 UDP 包的源地址里拿到发送方的 IP(通常是 DNS Resolver 的 IP)。
- 查表匹配:在 GeoIP 数据库里查这个 IP,看落在哪个地址段里。比如 223.5.5.0/24 属于中国-浙江-杭州-阿里巴巴。
- 匹配策略:根据查询结果,和预先配置的策略匹配。比如中国的请求返回一组国内 IP,北美的请求返回一组美国 IP。
- 返回结果:把匹配到的 IP 塞回 DNS 响应里发回去。
但这里有个根本前提:GeoDNS 只能保证策略上给一个看起来合理的候选节点,它并不能保证这是网络路径上真正最近或延迟最低的节点。
不同区域查同一个 DNS 域名
下面是我用不同地区的视角查询 www.bilibili.com 得到的结果:
在国内查询(使用阿里 DNS)
$ dig @223.5.5.5 www.bilibili.com +short | nali
a.w.bilicdn1.com.
218.60.18.15 [中国–辽宁–阜新 联通]
221.204.56.86 [中国–山西–太原 联通]
218.60.18.18 [中国–辽宁–阜新 联通]
221.204.56.91 [中国–山西–太原 联通]
218.60.18.17 [中国–辽宁–阜新 联通]
218.60.18.16 [中国–辽宁–阜新 联通]
221.204.56.95 [中国–山西–太原 联通]
221.204.56.94 [中国–山西–太原 联通]
221.204.56.92 [中国–山西–太原 联通]
221.204.56.93 [中国–山西–太原 联通]
218.60.18.13 [中国–辽宁–阜新 联通]
218.60.18.14 [中国–辽宁–阜新 联通]
在洛杉矶服务器上查询(使用当地默认 DNS)
$ dig www.bilibili.com +short | nali
a.w.bilicdn1.com.
i.w.bilicdn1.com.
192.254.90.179 [美国 加利福尼亚州洛杉矶Zenlayer]
192.254.90.178 [美国 加利福尼亚州洛杉矶Zenlayer]
148.153.64.18 [美国]
148.153.56.163 [美国]
148.153.56.162 [美国]
148.153.46.90 [美国]
148.153.45.10 [美国 加利福尼亚州洛杉矶首都在线数据中心]
同一个域名,两个不同的位置,返回的 IP 完全不同。国内的请求被解析到了国内的 CDN 节点,洛杉矶的请求则被导向了当地数据中心节点。
但这里要提醒一点:这个实验并不等于用户在该地区访问,而是使用该地区的 Resolver 访问。真正被 GeoDNS 看到并做决策的,是 Resolver 的 IP,而不是你的 IP。这一点非常关键,也是 GeoDNS 最容易出问题的地方。
GeoDNS 并不是用户的位置
大多数用户不会直接访问权威 DNS,而是通过本地 DNS Resolver。这意味着 GeoDNS 判断用户在哪里时,依据的是 Resolver 的 IP 地址。在大量公共 DNS 场景下,这个 IP 的地理位置可能完全偏离用户真实位置,甚至跨洲。
Resolver IP 问题
很多 ISP 会把 DNS 请求集中转发到省会节点;企业出口统一 NAT 到另一城市;使用 DoH / DoT 时,查询可能直接走到千里之外的节点。Resolver 和用户不在同一个城市、甚至不在同一个国家,是非常常见的情况。
公共 DNS 的影响
如果你用的是 8.8.8.8(Google DNS)或 1.1.1.1(Cloudflare DNS),这些公共 DNS 的节点分布全球,但你的查询不一定从离你最近的节点发出。结果就是你明明在上海,GeoDNS 却把你判定成了来自新加坡或美国。
EDNS Client Subnet(ECS)
为了缓解上面的问题,业界引入了 EDNS Client Subnet(ECS)。它允许 Resolver 在查询时附带用户的子网信息(通常是 /24),让权威 DNS 能更精确地判断用户位置。
但 ECS 在实际互联网中并没有成为可靠的标准解:
- 大量公共 DNS 出于隐私优先策略,直接关闭了 ECS。
- CDN 厂商也不完全信任 ECS 数据,因为它有被伪造或污染的风险。
所以即便有了 ECS,GeoDNS 的定位也做不到百分百准确。
TTL 对 GeoDNS 的限制
DNS 结果是有缓存的,而这个缓存时间由 TTL(Time To Live)控制。GeoDNS 的调度策略再灵活,也敌不过各级 DNS 缓存的固执。
缓存层级
从用户本地系统、浏览器、路由器,到运营商 DNS、公共 DNS,几乎每一层都可能缓存解析结果。只要 TTL 没过期,这些缓存就会原样返回旧的 IP。
实时性 vs 成本
TTL 设得太短,DNS 查询量会暴涨,权威 DNS 压力增大;TTL 设得太长,流量切换就慢。大多数生产环境的 TTL 在 60 秒到 300 秒之间,灾备切换时这个延迟已不容忽略。
为了绕过 TTL 限制,工程上常见的做法包括:
- 使用极短 TTL(20~60 秒),牺牲一部分查询量换取切换速度。
- 结合 HTTP 302 重定向做二次调度,把最终选择权收回到应用层。
- 或者干脆依赖 Anycast,让网络层实时调整路径,避免在 DNS 层频繁切换。
为什么 failover 经常不及时
当你需要把某个故障机房的流量切走时,GeoDNS 可以立刻修改解析结果,但用户端的缓存不会立刻失效。在 TTL 过期之前,仍有大量请求会涌向故障节点。这就是为什么很多故障切换不够及时的根本原因。
Anycast 也不是完美的
Anycast 虽然比 GeoDNS 更实时、更细粒度,但它也不是银弹。因为它完全依赖 BGP 路由,而 BGP 的收敛和策略并不总是理想的:
- 路由震荡可能导致流量在不同 POP 之间来回切换。
- 某些运营商的策略路由可能把流量引到非最优节点。
- 故障时的收敛速度取决于 BGP 的更新传播,而不是应用层能直接控制的。
因此很多大型 CDN 会在 Anycast 之上再叠加健康检查和流量工程机制,用来修正 BGP 的 suboptimal routing。
现实世界是怎么用它们的
CDN
CDN 是最典型的场景。大型 CDN 厂商通常会混合使用 GeoDNS 和 Anycast:GeoDNS 负责在 Region 级别把用户导入某个大区的 IP 池,然后 Anycast 在 POP 级别完成细粒度的就近接入。
那为什么不干脆只保留 Anycast?因为 GeoDNS 仍然有其不可替代的价值:
- 跨大区流量隔离:出于合规或成本考虑,需要把某些地区的流量导到特定机房。
- Region 级别灾备切换:当整个大区不可用时,通过 DNS 快速把流量切走。
- 避免跨洲回源:让用户的请求尽量落在和内容副本相同的区域内,减少骨干网穿越。
多地域部署
如果你的服务在 AWS 东京、新加坡和法兰克福都有部署,GeoDNS 可以把亚洲用户导到东京或新加坡,欧洲用户导到法兰克福。但如果你在这些机房前面再套一层 Anycast,用户的实际接入点可能还会在 POP 级别进一步细分。
灾备切换
当某个地域的机房出现故障时,可以通过 GeoDNS 快速将该地域的解析结果切换到备用机房。虽然受 TTL 限制做不到秒级生效,但依然是成本较低的手段之一。而对延迟要求极高的场景,Anycast 的自动收敛往往更值得信赖。
常见坑
误判用户位置
公共 DNS、企业出口 NAT、VPN 都会导致 GeoDNS 误判。不要假设 GeoDNS 的结果一定正确。
TTL 配置错误
上线前把 TTL 设成了 86400 秒,等要切换时发现各级 DNS 仍在缓存旧记录。建议变更前先把 TTL 调低,稳定后再适当提高。
GeoIP 数据库精度问题
GeoIP 数据库不是万能的,IP 归属地信息会变动,免费版数据库更新频率也有限。如果你追求高精度,需要付费订阅并及时更新。
以为关了 GeoDNS 就近访问就失效了
这是一个常见的误解。即使 GeoDNS 完全关闭,只要使用 Anycast,CDN 仍然可以正常实现就近访问。这也是越来越多厂商把重心从 DNS 层调度转移到网络层调度的原因之一。
总结
GeoDNS 和 Anycast 都是流量调度的工具,但它们的角色和边界完全不同:
- GeoDNS 在 DNS 查询阶段基于来源 IP 的地理位置返回不同的解析结果,通常工作在 Region 级别,简单、成本低,但受限于 Resolver 位置和 DNS 缓存。
- Anycast 在网络路由层面通过 BGP 实现接入点选择,工作在 POP 级别,是现代 CDN 的核心调度手段,但它优化的是路由策略,而不是严格的物理距离。