Skip to content

Latest commit

 

History

History
257 lines (171 loc) · 23.9 KB

DNS及HTTPDNS.md

File metadata and controls

257 lines (171 loc) · 23.9 KB

DNS及HTTPDNS

image

DNS简介

DNS(Domain Name System):域名系统,是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCP和UDP端口53。当前,对于每一级域名长度的限制是63个字符,域名总长度则不能超过253个字符。它的作用是根据域名查出IP地址,它是HTTP协议的前提,只有将域名正确的解析成IP地址后,后面的HTTP流程才能进行,所以一般做网络优化会首选优化DNS。

根据域名查询IP,可以使用dig和host命令,例如下面查询百度的IP,我们直接浏览器访问220.181.38.148也是可以放到baidu的

dig baidu.com
// 查询参数和统计
; <<>> DiG 9.10.6 <<>> baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50292
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 5, ADDITIONAL: 6
// 查询内容
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;baidu.com.         IN  A // 域名baidu.com的A记录,A是Address,注意com后面多了一个点
// DNS服务器的答复,有两个IP,600表示600s内不用重新查询
;; ANSWER SECTION:
baidu.com.      600 IN  A   220.181.38.148
baidu.com.      600 IN  A   39.156.69.79
// baidu.com的NS记录(Name Server),即哪些服务器负责管理baidu.com的DNS记录
;; AUTHORITY SECTION:
baidu.com.      86400   IN  NS  ns3.baidu.com.
baidu.com.      86400   IN  NS  dns.baidu.com.
baidu.com.      86400   IN  NS  ns7.baidu.com.
baidu.com.      86400   IN  NS  ns2.baidu.com.
baidu.com.      86400   IN  NS  ns4.baidu.com.
// 上一段返回的域名服务器的IP地址
;; ADDITIONAL SECTION:
dns.baidu.com.      86400   IN  A   202.108.22.220
ns2.baidu.com.      86400   IN  A   220.181.33.31
ns3.baidu.com.      86400   IN  A   112.80.248.64
ns4.baidu.com.      86400   IN  A   14.215.178.80
ns7.baidu.com.      86400   IN  A   180.76.76.92
// DNS服务器的一些传输信息,本机的DNS服务器是172.22.1.253,查询端口是53(DNS服务器默认端口)
;; Query time: 16 msec
;; SERVER: 172.22.1.253#53(172.22.1.253)
;; WHEN: Wed Dec 18 17:25:52 CST 2019
;; MSG SIZE  rcvd: 240

host命令是dig的简版:

host baidu.com
baidu.com has address 220.181.38.148
baidu.com has address 39.156.69.79
baidu.com mail is handled by 20 jpmx.baidu.com.
baidu.com mail is handled by 20 mx50.baidu.com.
baidu.com mail is handled by 10 mx.maillb.baidu.com.
baidu.com mail is handled by 15 mx.n.shifen.com.
baidu.com mail is handled by 20 mx1.baidu.com.

从上面dig命令执行的结果来看,域名baidu.com显示为baidu.com.这里为啥会多一个.。其实baidu.com 的真正域名时baidu.com.root。简写为baidu.com.。因为,根域名.root对于所有域名都是一样的,所以平时是省略的。 根域名的下一级,叫做"顶级域名"(top-level domain,缩写为TLD),比如.com、.net;再下一级叫做"次级域名"(second-level domain,缩写为SLD),比如www.example.com里面的.example,这一级域名是用户可以注册的;再下一级是主机名(host),比如www.example.com里面的www,又称为"三级域名",这是用户在自己的域里面为服务器分配的名称,是用户可以任意分配的。

DNS服务器根据域名的层级,进行分级查询。需要明确的是,每一级域名都有自己的NS记录,NS记录指向该级域名的域名服务器。这些服务器知道下一级域名的各种记录。所谓"分级查询",就是从根域名开始,依次查询每一级域名的NS记录,直到查到最终的IP地址,过程大致如下:

  1. 从"根域名服务器"查到"顶级域名服务器"的NS记录和A记录(IP地址)
  2. 从"顶级域名服务器"查到"次级域名服务器"的NS记录和A记录(IP地址)
  3. 从"次级域名服务器"查出"主机名"的IP地址

image

仔细看上面的过程,你可能发现了,没有提到DNS服务器怎么知道"根域名服务器"的IP地址。这是因为"根域名服务器"的NS记录和IP地址一般是不会变化的,所以内置在DNS服务器里面。目前,世界上一共有十三组根域名服务器,从A.ROOT-SERVERS.NET一直到M.ROOT-SERVERS.NET。

DNS服务器的分类

根域名服务器

全球13台顶级DNS服务器,存储了所有后缀的域名服务器IP地址,根据域名后缀查询出对应所属的域名服务器IP。

域名服务器

存储了所有域名的注册信息及NS服务器地址,根据域名注册信息上记录的NS地址找到提供域名解析服务的DNS解析服务器(权威DNS)所在IP.

权威解析服务器

存储了提供解析服务的所有域名解析记录,可直接查询出访问域名所添加的解析记录值. DNS权威服务器保存着域名空间中部分区域的数据。如果DNS服务器负责管辖一个或多个区域时,称此DNS服务器为这些区域的权威服务器。 权威DNS即最终决定域名解析结果的服务器,开发者可以在权威DNS上配置、变更、删除具体域名的对应解析结果信息。阿里云云解析( https://wanwang.aliyun.com/domain/dns )即权威DNS服务提供商。

递归服务器

递归DNS(或运营商DNS)又称为Local DNS,它没有域名解析结果的决定权,但代理了用户向权威DNS获取域名解析结果的过程。根据用户的解析访问请求,向上级DNS解析服务器发起查询请求,再将最终查询出的域名解析记录指向地址告知请求设备。根据用户的解析访问请求,向上级DNS解析服务器发起查询请求,再将最终查询出的域名解析记录指向地址告知请求设备。

递归DNS上有缓存模块,当目标域名存在缓存解析结果并且TTL未过期时(每个域名都有TTL时间,即有效生存时间,若域名解析结果缓存的时间超过TTL,需要重新向权威DNS获取解析结果),递归DNS会返回缓存结果,否则,递归DNS会一级一级地查询各个层级域名的权威DNS直至获取最终完整域名的解析结果。

  • 公共DNS

公共DNS是递归DNS的一种特例,它是一种全网开放的递归DNS服务,而传统的递归DNS信息一般由运营商分发给用户。一个比较典型的公共DNS即Google的8.8.8.8,我们可以通过在操作系统配置文件中配置公共DNS来代替Local DNS完成域名解析流程。

在实际的使用过程中,我们通常不需要手工指定自己的Local DNS地址。运营商会通过DHCP协议在系统网络初始化阶段将Local DNS地址分配给我们的计算机。当我们需要使用公共DNS服务时,我们就必须手工指定这些服务的地址。以Linux为例,我们可以通过在'/etc/resolv.conf'中添加Local DNS地址项来改变本机Local DNS的地址。

DNS解析过程

image

  1. 在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。

  2. 如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。

  3. 如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找TCP/ip参数中设置的首选DNS服务器,在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。

  4. 如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。

  5. 如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后会判断这个域名(.com)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com域的下一级DNS服务器地址(qq.com)给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找qq.com域服务器,重复上面的动作,进行查询,直至找到www.qq.com主机。

  6. 如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把转请求转至上上级,以此循环。不管是本地DNS服务器用是是转发,还是根提示,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机。

解析顺序

  1. 浏览器缓存
    当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的IP地址(若曾经访问过该域名且没有清空缓存便存在)
  2. 系统缓存
    当浏览器缓存中无域名对应IP则会自动检查用户计算机系统Hosts文件DNS缓存是否有该域名对应IP;
  3. 路由器缓存
    当浏览器及系统缓存中均无域名对应IP则进入路由器缓存中检查,以上三步均为客服端的DNS缓存;
  4. ISP(互联网服务提供商)DNS缓存
    当在用户客服端查找不到域名对应IP地址,则将进入ISP DNS缓存中进行查询。比如你用的是电信的网络,则会进入电信的DNS缓存服务器中进行查找;
  5. 根域名服务器
    当以上均未完成,则进入根服务器进行查询。全球仅有13台根域名服务器,1个主根域名服务器,其余12为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com)服务器IP告诉本地DNS服务器;
  6. 顶级域名服务器
    顶级域名服务器收到请求后查看区域文件记录,若无则将其管辖范围内主域名服务器的IP地址告诉本地DNS服务器;
  7. 主域名服务器
    主域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确纪录;
  8. 保存结果至缓存
    本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个IP地址与web服务器建立链接。

DNS的记录类型

域名与IP之间的对应关系,称为"记录"(record)。根据使用场景,"记录"可以分成不同的类型(type),前面已经看到了有A记录和NS记录。

常见的DNS记录类型如下。

  • A:地址记录(Address),返回域名指向的IP地址。
  • NS:域名服务器记录(Name Server),返回保存下一级域名信息的服务器地址。该记录只能设置为域名,不能设置为IP地址。
  • MX:邮件记录(Mail eXchange),返回接收电子邮件的服务器地址。
  • CNAME:规范名称记录(Canonical Name),返回另一个域名,即当前查询的域名是另一个域名的跳转。
  • PTR:逆向查询记录(Pointer Record),只用于从IP地址查询域名。

一般来说,为了服务的安全可靠,至少应该有两条NS记录,而A记录和MX记录也可以有多条,这样就提供了服务的冗余性,防止出现单点失败。

CNAME记录主要用于域名的内部跳转,为服务器配置提供灵活性,用户感知不到。

DNS存在的问题

  • 不稳定:DNS劫持或者故障,导致服务不可用
  • 不准确: LocalDNS的调度并不一定是就近原则,某些小运营商没有DNS服务器,直接调用其他运营商的DNS服务器,最终直接跨网传输。例如:用户侧是移动运营商,调度到了电信的IP,造成访问慢,甚至访问受限等问题
  • 不及时:运营商可能会修改DNS的TTL(Time-To-Live,DNS缓存时间),导致DNS的修改,延迟生效。

域名劫持

域名劫持一直是困扰许多开发者的问题之一,其表现即域名A应该返回的DNS解析结果IP1被恶意替换为了IP2,导致A的访问失败或访问了一个不安全的站点。下面我们一起看看几种常见的域名劫持的场景。

  • 一种可能的域名劫持方式即黑客侵入了宽带路由器并对终端用户的Local DNS进行篡改,指向黑客自己伪造的Local DNS,进而通过控制Local DNS的逻辑返回错误的IP信息进行域名劫持。另一方面,由于DNS解析主要是基于UDP协议,除了上述攻击行为外,攻击者还可以监听终端用户的域名解析请求,并在Local DNS返回正确结果之前将伪造的DNS解析响应传递给终端用户,进而控制终端用户的域名访问行为。

  • 另一种我们最常碰到的域名劫持现象是缓存污染。我们知道在接收到域名解析请求时,Local DNS首先会查找缓存,如果缓存命中就会直接返回缓存结果,不再进行递归DNS查询。这时候如果Local DNS针对部分域名的缓存进行更改,比如将缓存结果指向第三方的广告页,就会导致用户的访问请求被引导到这些广告页地址上。对比第一种攻击,这类缓存污染往往能带来更明显的群体伤害,比如某个省份某个运营商的用户群可能因为该地区Local DNS的缓存污染而导致访问服务异常。这类缓存污染行为往往是间歇性、局部性发生的,没有明显的规律,导致开发者很难对其进行量化、评估、预防。

调度不精准

除了域名劫持问题,基于传统Local DNS的域名解析还会带来域名调度精准性的问题。对于类似CDN域名访问这类需要按地域、运营商进行智能解析调度的场景,精准调度的诉求是十分强烈的。

关于调度不精准的原因,我们主要可以从两个方面来探究一下。第一个常见的问题即解析转发。

部分Local DNS供应商为了降低运营成本,会将请求到自己节点的域名解析请求转发给其他供应商的Local DNS节点,假如用户请求解析一个CDN域名cdn.aliyun.com,用户分配到的Local DNS A为了节省成本,把该次请求转发给了另一运营商的Local DNS B,权威DNS在进行域名解析时会根据Local DNS的IP信息进行智能调度,即权威DNS会根据Local DNS B的IP78.29.29.1进行调度,分配与78.29.29.1相同运营商并且地理位置最近的CDN节点78.29.29.2,然而这个CDN节点对于终端135.35.35.1而言并不是最优的CDN节点,他们分属不同的运营商,并且地理位置上可能相隔很远。这类解析转发行为会严重影响域名解析的精准性并对用户业务访问延迟带来影响。

image

如上图所示,部分运营商Local DNS的布点受成本因素制约分布并不均匀,比如在东部地区部署比较密集,但在西部地区部署比较稀疏。这时候当一位西藏的用户准备访问CDN节点时,我们预期他应该会被调度到西藏的CDN节点A上以实现就近接入和访问加速。但由于Local DNS的资源有限,西部地区的终端用户被统一调度到青海的Local DNS B上,这时候权威DNS根据Local DNS B的IP进行CDN域名的智能解析,并将青海的CDN节点B返回给西藏用户,导致用户的网络访问延迟上升。另一种我们实际发现的情况是Local DNS的分配甚至并非遵循就近原则,比如有实际案例显示西藏的用户甚至被分配了北京的Local DNS节点C,导致西藏的用户在进行CDN资源访问时被调度到了北京的CDN节点C上,类似的由于调度精度的缺失带来的访问体验的影响是非常严重的。

解析生效滞后

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

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

DNS首次查询或缓存过期后的查询,需要递归遍历多个DNS服务器以获取最终的解析结果,这增加了网络请求的前置延时时间。特别是在移动互联网场景下,移动网络质量参差不齐,弱网环境的RTT时间可能高达数百毫秒,对于一次普通的业务请求而言,上述延时是非常沉重的负担。另一方面,弱网环境下的解析超时、解析失败等现象屡见不鲜,如何合理优化DNS解析对于整体网络访问质量的提升至关重要。

通过上面的介绍,可以知道传统域名解析面临的诸多问题与挑战本质根源在于Local DNS的服务质量不可控,如果有一个更安全、稳定、高效的递归DNS服务帮助我们代理了域名解析的过程,上述问题看起来就可以彻底地得到解决。HTTPDNS在这样的背景下应运而生。

HTTPDNS

HTTPDNS使用HTTP协议进行域名解析,代替现有基于UDP的DNS协议,域名解析请求直接发送到HTTPDNS服务端,从而绕过运营商的Local DNS,有效的防止了域名劫持,提高域名解析的效率,如下图所示。

image

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

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

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

精准调度

传统域名解析的调度精准性问题,本质根源在于Local DNS的部署和分配机制上。由于碎片化的管理方式,这些环节的服务质量同样很难得到保障。HTTPDNS在递归解析实现上优化了与权威DNS的交互,通过edns-client-subnet协议将终端用户的IP信息直接交付给权威DNS,这样权威DNS就可以忽略Local DNS IP信息,根据终端用户的IP信息进行精准调度,避免Local DNS的坐标干扰(当然上述精准调度方案的前提是权威DNS需要支持edns-client-subnet,可喜的是当前主流的权威DNS服务都已支持该协议)。精准调度的流程示例如下。

实时生效

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

在DNS解析延迟方面,由于HTTPDNS基于HTTP协议,而HTTP基于TCP协议,对比传统的UDP传输多了一些冗余的握手环节,因此从原理上而言网络请求方面的开销并没有降低。但在实际使用过程中,我们可以通过端上的策略来实现一个零延迟DNS解析的方案。

预解析

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

在客户端实际使用HTTPDNS的过程中,有一个大家需要关注的点。标准的Web服务器(以Nginx为例)一般会将HTTP请求头中的Host头的值作为请求的域名信息进行处理(取决于服务端的配置,但一般情况都如此)。比如当我们通过标准的网络库访问www.aliyun.com/index.html这个地址时,发出的网络请求一般是这样的:

GET /index.html HTTP/1.1
Host: www.aliyun.com
User-Agent: curl/7.43.0
Accept: */*

使用HTTPDNS后,我们需要将HTTP请求URL中的Host域(注意这里的Host域指的是URL中的Host字段,而非HTTP请求头中的Host头)替换为HTTPDNS解析获得的IP,这时由于标准的网络库会将URL中的Host域赋值给HTTP请求头中的Host头,发出的网络请求如下:

GET /index.html HTTP/1.1
Host: 140.205.63.8
User-Agent: curl/7.43.0
Accept: */*

智能缓存

通过预解析获取的IP有一定的TTL有效时间,我们需要合理地缓存下来进行管理。操作系统本身的DNS缓存粒度比较粗,在客户端我们可以应用更细粒度的缓存管理来提升解析效率。比如在不同的网络运营商环境下,对CDN域名的解析结果会发生变化,当我们使用电信WIFI时,DNS解析会返回就近的电信CDN节点IP,当我们使用联通3G时,DNS解析会返回就近的联通CDN节点IP,针对不同运营商的解析结果缓存可以确保我们在网络切换时能够快速地进行网络请求,减免DNS解析带来的额外开销。甚至更激进的,我们可以做本地的持久化缓存,当下一次APP启动时直接读取缓存用于网络访问,以提升首屏加载的速度。

懒加载

懒加载策略的实施可以让我们真正实现DNS的零延迟解析。所谓懒加载策略,核心的实现思路如下:业务层的域名解析请求只和缓存进行交互,不实际发生网络解析请求。如果缓存中存在记录,不论过期与否,直接返回业务层缓存中的记录; 如果缓存中的记录已过期,后台发起异步网络请求进行HTTPDNS解析。

这里提两条大厂公开的数据,对腾讯的产品,在接入HTTPDNS后,用户平均延迟下降超过 10%,访问失败率下降超过五分之一。而百度App的Feed业务,Android劫持率由0.25%降低到0.05%。

参考: