术→技巧, 运维

移动域名解析HTTPDNS

钱魏Way · · 629 次浏览
!文章内容如有错误或排版问题,请提交反馈,非常感谢!

HTTPDNS简介

传统域名解析面临的诸多问题与挑战本质根源在于LocalDNS的服务质量不可控,如果有一个更安全、稳定、高效的递归DNS服务帮助我们代理了域名解析的过程,这些问题就可以彻底地得到解决。

HTTPDNS在这样的背景下应运而生。我们一起来看看HTTPDNS的基本概念以及它是如何解决传统DNS解析面临的问题的。

运营商劫持

DNS劫持就是通过劫持了DNS服务器,通过某些手段取得某域名的解析记录控制权,进而修改此域名的解析结果,导致对该域名的访问由原IP地址转入到修改后的指定IP,其结果就是对特定的网址不能访问或访问的是假网址,从而实现窃取资料或者破坏原有正常服务的目的。

HTTPDNS使用HTTP协议进行域名解析,代替现有基于UDP的DNS协议,域名解析请求直接发送到HTTPDNS服务端,从而绕过运营商的LocalDNS。

HTTPDNS代替了传统的LocalDNS完成递归解析的功能,基于HTTP协议的设计可以适用于几乎所有的网络环境,同时保留了鉴权、HTTPS等更高安全性的扩展能力,避免恶意攻击劫持行为。另一方面,商业化的HTTPDNS服务(比如阿里云HTTPDNS、腾讯云HTTPDNS)缓存管理有严格的SLA保障,避免了类似LocalDNS的缓存污染的问题。

域名缓存

LocalDNS缓存了域名的解析结果,不向权威DNS发起递归。

LocalDNS要把域名解析结果进行原因有以下几个:

  • 保证用户访问流量在本网内消化:国内的各互联网接入运营商的带宽资源、网间结算费用、IDC机房分布、网内ICP资源分布等存在较大差异。为了保证网内用户的访问质量,同时减少跨网结算,运营商在网内搭建了内容缓存服务器,通过把域名强行指向内容缓存服务器的IP地址,就实现了把本地本网流量完全留在了本地的目的。
  • 推送广告:有部分LocalDNS会把部分域名解析结果的所指向的内容缓存,并替换成第三方广告联盟的广告。

这种类型的行为就是我们常说的域名缓存,域名缓存会导致用户产生以下的访问异常:

  • 仅对80端口的http服务做了缓存,如果域名是通过https协议或其它端口提供服务的,用户访问就会出现失败。比如支付服务、游戏通过指定端口连接connectserver服务等。
  • 缓存服务器的运维水平参差不齐,时有出现缓存服务器故障导致用户访问异常的问题。

在域名解析生效周期方面,HTTPDNS也有着传统域名解析体系所无法具备的能力。前面我们提到由于各个地区的LocalDNS是独立维护的,服务质量参差不齐,缓存实现不一,因此导致的解析变更全网生效滞后的问题,在商业化的HTTPDNS服务上就不会存在(HTTPDNS严格遵循DNSTTL限制进行缓存更新)。另一方面,即便我们假设LocalDNS严格遵循域名TTL时间进行缓存管理(这里我们假设运维配置的域名TTL时间为5min),当我们的业务受到攻击并需要快速进行切换时,LocalDNS也会遵循域名TTL,在持续5min的时间段内返回旧IP信息,这5min的业务影响对于中大型企业而言是一个不小的损失(对于电商类的大型企业,5min的访问异常可能意味着几百万的交易额下跌)。以阿里云HTTPDNS服务,HTTPDNS在快速生效方面有专有的方案,配合阿里云的权威DNS服务云解析(我们的域名都是部署在阿里云的权威DNS服务云解析上面),用户在权威DNS变更的解析结果将快速同步给HTTPDNS,覆盖原有的缓存记录,帮助用户实现毫秒级的域名解析切换。

解析转发:

除了域名缓存以外,运营商的LocalDNS还存在解析转发的现象。解析转发是指运营商自身不进行域名递归解析,而是把域名解析请求转发到其它运营商的递归DNS上的行为。正常的LocalDNS递归解析过程是这样的:

而部分小运营商为了节省资源,就直接将解析请求转发到了其它运营的递归LocalDNS上去了:

这样的直接后果就是权威DNS收到的域名解析请求的来源IP就成了其它运营商的IP,最终导致用户流量被导向了错误的IDC,用户访问变慢。

LocalDNS递归出口NAT

LocalDNS递归出口NAT指的是运营商的LocalDNS按照标准的DNS协议进行递归,但是因为在网络上存在多出口且配置了目标路由NAT,结果导致LocalDNS最终进行递归解析的时候的出口IP就有概率不为本网的IP地址:

这样的直接后果就是GSLBDNS收到的域名解析请求的来源IP还是成了其它运营商的IP,最终导致用户流量被导向了错误的IDC,用户访问变慢。

解析生效滞后

部分业务场景下开发者对域名解析结果变更的生效时间非常敏感(这部分变更操作是开发者在权威DNS上完成的),比如当业务服务器受到攻击时,我们需要最快速地将业务IP切换到另一组集群上,这样的诉求在传统域名解析体系下是无法完成的。

LocalDNS的部署是由各个地区的各个运营商独立部署的,因此各个LocalDNS的服务质量参差不齐。在对域名解析缓存的处理上,各个独立节点的实现策略也有区别,比如部分节点为了节省开支忽略了域名解析结果的TTL时间限制,导致用户在权威DNS变更的解析结果全网生效的周期非常漫长(我们已知的最长生效时间甚至高达48小时)。这类延迟生效可能直接导致用户业务访问的异常。

商业化的HTTPDNS服务,都具备99.99%的高可用性,确保域名解析服务稳定可靠。

HTTPDNS客户端直接通过IP来进行域名解析请求的,HTTPDNS SDK内部维护一个IP轮询池,当某个IP不可用时,会自动切换其他的IP,并且IP轮询池也会更新。

HTTPDNS服务端方面,拿阿里云的HTTPDNS来说,在全球有数十个服务集群,各个服务集群互相备份,具备异地容灾备份功能,当某个服务集群不可用时,会自动切换到其他的服务集群,可以确保解析和缓存正常。

HTTPDNS原理

HttpDNS的原理非常简单,主要有两步:

  • 客户端直接访问 HttpDNS 接口,获取业务在域名配置管理系统上配置的访问延迟最优的 IP。(基于容灾考虑,还是保留次选使用运营商 LocalDNS 解析域名的方式)
  • 客户端向获取到的 IP 后就向直接往此 IP 发送业务协议请求。以 Http 请求为例,通过在 header 中指定 host 字段,向 HttpDNS 返回的 IP 发送标准的 Http 请求即可。

HttpDNS 优势

从原理上来讲,HttpDNS 只是将域名解析的协议由 DNS 协议换成了 Http 协议,并不复杂。但是这一微小的转换,却带来了无数的收益:

  • 根治域名解析异常:由于绕过了运营商的 LocalDNS,用户解析域名的请求通过 Http 协议直接透传到了 HttpDNS 服务器 IP 上,用户在客户端的域名解析请求将不会遭受到域名解析异常的困扰。
  • 调度精准:HttpDNS 能直接获取到用户 IP,通过结合腾讯自有专利技术生成的 IP 地址库以及测速系统,可以保证将用户引导的访问最快的 IDC 节点上。
  • 实现成本低廉:接入 HttpDNS 的业务仅需要对客户端接入层做少量改造,无需用户手机进行 root 或越狱;而且由于 Http 协议请求构造非常简单,兼容各版本的移动操作系统更不成问题;另外 HttpDNS 的后端配置完全复用现有权威 DNS 配置,管理成本也非常低。总而言之,就是以最小的改造成本,解决了业务遭受域名解析异常的问题,并满足业务精确流量调度的需求。
  • 扩展性强:HttpDNS 提供可靠的域名解析服务,业务可将自有调度逻辑与 HttpDNS 返回结果结合,实现更精细化的流量调度。比如指定版本的客户端连接请求的 IP 地址,指定网络类型的用户连接指定的 IP 地址等。
  • 用户连接失败率下降:通过算法降低以往失败率过高的服务器排序,通过时间近期访问过的数据提高服务器排序,通过历史访问成功记录提高服务器排序。
  • 平均访问延迟下降:由于是 IP 直接访问省掉了一次 domain 解析过程,通过智能算法排序后找到最快节点进行访问。

HTTPDNS 搭建

HTTPDNS 设计中关键点

  • 安全策略:HTTPDNS 查询是基于标准的 HTTP 协议,但是如果为了保证安全,可以使用 HTTPS;
  • IP 选取策略:HTTPDNS 服务将最优 IP 按照顺序下发,客户端默认选取第一个,校验连通性 OK 就使用,如果不 OK,选用下一个校验;
  • 缓存过期策略:后端动态下发域名的 TTL 时间,当域名的 TTL 超时后,如果没有新的 IP 将继续沿用老的 IP,也可以降级成 LocalDNS 返回的 IP。
  • 批量拉取策略:在应用冷启动或网络切换时候,批量拉取域名和 IP 列表的映射数据,缓存下来;以便在后续请求中使用到,预期提升精准调度能力。
  • 降级策略:当 HTTPDNS 服务不可用&本地也没有缓存或者缓存失效时,降级成运营商的 LocalDNS 方案;当 HTTPDNS 服务&LocalDNS 服务双双不可用的情况下,可以使用 BACKUP IP;

HTTPDNS 最佳实践

移动 APP 的域名解析机制,新的流程参考如下:

需要注意的是,发起网络请求时,在本地无缓存,或缓存已过期的情况下,直接使用 localDNS 解析,并同时异步更新本地 DNS 缓存。

Failedover 策略降级

虽然 HttpDNS 已经接入 BGP Anycast,并实现了多地跨机房容灾。但为了保证在最坏的情况下客户端域名解析依然不受影响。建议采用以下的 failover 策略:

  • 第一步先向 HttpDNS 发起域名查询请求
  • 如果 HttpDNS 查询返回的结果不是一个 IP 地址(结果为空、结果非 IP、连接超时等),则通过本地 LocalDNS 进行域名解析。超时时间建议为 5s。

不管是因为什么原因,当通过 HTTPDNS 服务无法获得域名对应的 IP 时,都必须降级:使用标准的 DNS 解析,通过 LocalDNS 去解析域名。

缓存策略

移动互联网用户的网络环境比较复杂,为了尽可能地减少由于域名解析导致的延迟,建议在本地进行缓存。缓存规则如下:

  • 缓存时间。缓存时间建议设置为 120s 至 600s,不可低于 60s。
  • 缓存更新。缓存更新应在以下两种情形下进行:
    • 用户网络状态发生变化时:移动互联网的用户的网络状态由 3G 切 Wi-Fi,Wi-Fi 切 3G 的情况下,其接入点的网络归属可能发生变化。所以用户的网络状态发生变化时,需要重新向 HttpDNS 发起域名解析请求,以获得用户当前网络归属下的最优指向。
    • 缓存过期时:当域名解析的结果缓存时间到期时,客户端应该向 HttpDNS 重新发起域名解析请求以获取最新的域名对应的 IP。为了减少用户在缓存过期后重新进行域名解析时的等待时间,建议在 75%TTL 时就开始进行域名解析。如本地缓存的 TTL 为 600s,那么在第 600*0.75=450s 时刻,客户端就应该进行域名解析。

除了以上几点建议外,减少域名解析的次数也能有效的减少网络交互,提升用户访问体验。建议在业务允许的情况下,尽量减少域名的数量。如需区分不同的资源,建议通过 url 来进行区分。

异步请求、懒加载

异步请求策略:解析域名时,如果当前缓存中有 TTL 未过期的 IP,可直接使用;如果没有,则立刻让此次请求降级走原生 LocalDNS 解析,同时另起线程异步地发起 HTTPDNS 请求进行解析,更新缓存,这样后续解析域名时就能命中缓存。

  • 查询注册的 DNS 解析列表,若未注册返回 null
  • 查询缓存,若存在且未过期则返回结果,若不存在返回 null 并且进行异步域名解析更新缓存。
  • 若接口返回 null,降级到 localdns 解析策略。

懒加载策略的实施可以让我们真正实现 DNS 的零延迟解析。所谓懒加载策略,核心的实现思路如下:

  • 业务层的域名解析请求只和缓存进行交互,不实际发生网络解析请求。如果缓存中存在记录,不论过期与否,直接返回业务层缓存中的记录;
  • 如果缓存中的记录已过期,后台发起异步网络请求进行 HTTPDNS 解析;

下图描绘了预解析+懒加载的实现框架:

重试

访问 HTTPDNS 服务解析域名时,如果请求 HTTPDNS 服务端失败,即 HTTP 请求没有返回,可以进行重试。大部分情况下,这种访问失败是由于网络原因引起的,重试可以解决。

预解析

绝大多数的 APP 在应用初始化阶段都有一个启动期,我们可以在这个启动期做一些 preflight 工作,即在初始化阶段我们可以针对业务的热点域名在后台发起异步的 HTTPDNS 解析请求。这部分预解析结果在后续的业务请求中可以直接使用,进而消除首次业务请求的 DNS 解析开销,提升 APP 首页的加载速度。

HTTPS

发送 HTTPS 请求首先要进行 SSL/TLS 握手,握手过程大致如下:

  • 客户端发起握手请求,携带随机数、支持算法列表等参数。
  • 服务端收到请求,选择合适的算法,下发公钥证书和随机数。
  • 客户端对服务端证书进行校验,并发送随机数信息,该信息使用公钥加密。
  • 服务端通过私钥获取随机数信息。
  • 双方根据以上交互的信息生成 session ticket,用作该连接后续数据传输的加密密钥。

上述过程中,和 HTTPDNS 有关的是第 3 步,客户端需要验证服务端下发的证书,验证过程有以下两个要点:

  • 客户端用本地保存的根证书解开证书链,确认服务端下发的证书是由可信任的机构颁发的。
  • 客户端需要检查证书的 domain 域和扩展域,看是否包含本次请求的 host。

如果上述两点都校验通过,就证明当前的服务端是可信任的,否则就是不可信任,应当中断当前连接。

当客户端使用 HTTPDNS 解析域名时,请求 URL 中的 host 会被替换成 HTTPDNS 解析出来的 IP,所以在证书验证的第 2 步,会出现 domain 不匹配的情况,导致 SSL/TLS 握手不成功。

webview

Flutter

OkHttp

代理情况

当存在中间 HTTP 代理时,客户端发起的请求中请求行会使用绝对路径的 URL,在开启 HTTPDNS 并采用 IP URL 进行访问时,中间代理将识别您的 IP 信息并将其作为真实访问的 HOST 信息传递给目标服务器,这时目标服务器将无法处理这类无真实 HOST 信息的 HTTP 请求。

绝大多数场景下,在代理模式下关闭 HTTPDNS 功能。

注意事项

  • 设置的缓存 TTL 值不可太低(不可低于 60s),防止频繁进行 HtppDNS 请求。
  • 接入 HttpDNS 的业务需要保留用户本地 LocalDNS 作为容灾通道,当 HttpDNS 无法正常服务时(移动网络不稳定或 HttpDNS 服务出现问题),可以使用 LocalDNS 进行解析。
  • https 问题,需在客户端 hook 客户端检查证书的 domain 域和扩展域看是否包含本次请求的 host 的过程,将 IP 直接替换成原来的域名,再执行证书验证。或者忽略证书认证,类似于 curl -k 参数。
  • HttpDNS 请求建议超时时间 2-5s 左右。
  • 在网络类型变化时,如 4G 切换到 wifi,不同 wifi 间切换等,需要重新执行 HttpDNS 请求刷新本地缓存。

参考链接:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注