DNS是什么、DNS解析过程、DNS使用与优化
重点掌握: DNS是什么、DNS解析过程、DNS使用与优化
# 基础概念
# 域名系统(Domain Name System,DNS)
这是互联网的一项服务,采用类似目录树的等级结构,由域名解析器和域名服务器组成的。它作为将域名和IP地址相互映射的一个分布式数据库,提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务。
简而言之就是提供IP地址和域名之间互相转换的服务。
处于应用层
# 域名解析器
把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务。
# 域名服务器
保存有该网络中所有主机的域名和对应IP地址,并具有将域名转换为IP地址功能的服务器。域名服务器通常为客户机/服务器模式中的服务器方,它主要有两种形式:主服务器和转发服务器。
# IP与域名关系
- 域名必须对应一个IP地址
- 一个IP地址可以有0至多个域名,而IP地址不一定有域名。
# 域名解析
将域名映射为IP地址的过程就称为“域名解析”,简而言之就是在 DNS 上记录一条信息记录。域名解析的发展分为三阶段:
第一阶段是分布式的解析:解析工作由每一个主机负责。
指分在客户端上维护一个静态的文本文件,其中包含主机名和IP地址的映射。随着网络规模的扩大,分布式分辨率的有效性越来越低。
第二阶段集中式解析:由一台主机来完成的。
要求网络中有多台DNS服务器,负责维护域名/IP地址映射数据库。客户端从指定的服务器获取域名的地址信息。一旦客户端指定的DNS服务器不包含相应的数据,DNS服务器就会在网络中进行递归查询,并获取其他服务器上的地址信息。
目前阶段则是既有分布式的解析又有集中式解析,也就是服务器目前DNS。
# DNS与TCP/UDP的关系
DNS 协议建立在 UDP 或 TCP 协议之上,默认占用53号端口,通讯的三种方式如下:
UDP
默认通过 UDP 协议进行通讯。
TCP
广域网中不适合传输过大的 UDP 数据包,当报文长度超过了 512 字节时,主动使用 TCP 协议进行数据传输。
UDP+TCP
客户端使用 UDP 协议发送 DNS 请求,服务端发现响应报文超过了 512 字节,在截断的 UDP 响应报文中将 TC 设置为 1 ,以通知客户端该报文已经被截断,客户端收到之后再发起一次 TCP 请求。
UDP为什么更快:不用经过TCP三次握手,这样DNS服务器负载更低,响应更快。
# DNS作用
正向解析记录
通过域名找IP。浏览器并不能直接通过域名找到对应的服务器,而是要通过 IP 地址,但是域名更容易被人们所记住,所以通过域名解析将域名映射为IP地址。
反向解析记录
通过IP找域名,RTR反向解析。
提供主机别名服务
有着复杂主机名的主机可以有一个或者多个别名,例如aaa.xxx.com的主机可能还会有aaa.com和www.aaa.com两个别名,在这种情况下,aaa.xxx.com叫做规范主机名(canonical hostname)。主机别名的特征是比规范主机名更容易记忆,DNS可以提供根据主机别名获取规范主机名的服务。
负载均衡
一般来说,被繁忙访问的大型站点是分布在多台服务器上的, 这个时候,主机名和IP地址就不是一一对应的关系,而是一个主机名对应一个IP地址的集合。
在大量的,连续的多次访问中,DNS通过旋转IP地址达到负载均衡的目的:在向这个主机名发出DNS请求的时候,服务器会用包含全部这些IP地址的报文进行回答, 但在每个不同的回答中会旋转这些IP地址的摆放顺序,而客户机总向报文中排在最前的IP地址发出请求
CDN加速
对网页中的静态资源进行CDN节点缓存;在访问网页中的动态资源时从源站中调取,从而实现“动静分离”,达到加速的目的。“动静分离”的好处:用户访问网站时,静态资源直接从离自己最近的CDN节点缓存中获取,减少用户访问静态资源的时间,同时又降低源站服务器的带宽压力、静态资源访问压力。
CDN静态加速:
对网页中的静态资源(包括html文件、CSS文件、js文件、图片、flash动画等)进行CDN节点缓存,使得用户在访问网页中的静态资源时,调取CDN边缘节点缓存。
CDN动态加速:
CDN的DNS解析中通过动态链路探测,监控网络环境的变化,监控各地网络延迟,寻找到一条最稳定、最高效、最快速的路径,回源动态资源,从而实现动态资源(如asp、php、jsp等)加速。然后构成链路列表,绑定到DNS解析上,更新到CDN的本地域名服务器上。
# 整体架构
网址的解析是一个从右向左的过程,以www. baidu. com为例,“www. baidu. com”实际是“www. baidu. com. ” 这个 " . "就是根域名服务器,默认情况下为了方便用户通常会省略。浏览器在请求DNS的时候会自动加上。
![架构](/img/browser/架构. png)
# 根DNS服务器
掌握着所有顶级dns的ip和域名的对应关系,例如:.
因特网上有13个根DNS服务器, 其中大部分分布在北美洲
# 顶级DNS服务器
掌握着权威dns的ip和域名的对应关系。
分类 | 域名 |
---|---|
国家顶级域名 | 中国:cn, 美国:us,英国uk… |
通用顶级域名 | com公司企业,edu教育机构,gov政府部门,int国际组织,mil军事部门 ,net网络,org非盈利组织… |
反向域名 | arpa,用于PTR查询 |
# 权威DNS服务器
掌握着二级域名dns服务器的ip和域名的对应关系,例如:baidu. com。
在因特网上具有公共可访问的主机的每个组织机构必须提供公共可访问的DNS记录,这些记录将这些主机的名字映射为IP地址。 由组织机构的权威DNS服务器保存这些DNS记录,组织机构可以选择实现它自己的权威DNS服务器来保持这些记录,或者通过支付费用将这些记录存储在某个服务提供商的DNS服务器中。多数大学和大公司实现和维护它们自己基本的权威DNS服务器
# 二级域名的DNS服务器
掌握着你要访问的域名和ip的对应关系,例如:www. baidu. com
# 本地域名服务器
主机发送DNS查询请求时,查询首先要通过本地域名服务器,其作用如下:
代理转发:
主机和本地DNS服务器一般是相邻的,当主机发出DNS请求的时候,该请求会被发往本地DNS服务器,它起着代理的作用,并将该请求转发到DNS服务器层次结构中.
缓存:
本地DNS服务器可以通过缓存主机名/IP地址,减少对相同主机名的查询而消耗的时间,改善时延和性能.
# 解析过程
![解析过程](/img/browser/解析流程. png)
# 1. 浏览器缓存
首先会向浏览器的缓存中查找是否有访问记录。
方法: 在chrome可以通过地址栏中输入chrome://net-internals/#dns查看缓存的当前状态
# 2. 操作系统缓存
在系统运行中的内存里查找是否有缓存
方法:
在mac中: (1) 查看dns缓存:nslookup www. baidu. com (2) 清除系统中的DNS缓存:dscacheutil -flushcache
在windows中: (1) 查看dns缓存:ipconfig /displaydns (2) 强制更新缓存:ipconfig /flushdns
# 3. host文件
如果在缓存中查找不到,系统就会读取系统中预设的host文件
在windows中: hosts文件一般位于c:\windows\system32\drivers\etc
在mac中: (1) 打开finder (2) 快捷键组合Shift+Command+G,并在弹出框内输入/etc/hosts,回车即可看到hosts文件
# 4. 路由器缓存
部分路由器有缓存功能,访问过的域名会存在路由器上。
# 5. ISP DNS缓存
ISP( Internet Service Provider )互联网服务提供商,例如:中国电信等也会提供DNS服务,比较有名的是114. 114. 114. 114。
在本地查找不到的情况下,就会向ISP进行查询,ISP会在当前服务器的缓存内查找是否有记录,如果有则返回这个IP,若没有则会开始向根域名服务器请求查询。
# 6. 顶级/根DNS服务器
根域名收到请求后,会判别这个域名(. com)是授权给哪台服务器管理, 并返回这个顶级DNS服务器的IP。请求者收到这台顶级DNS的服务器IP后,会向该服务器发起查询,如果该服务器无法解析,该服务器就会返回下一级的DNS服务器IP(baidu. com),本机按照DNS架构继续查找,直到服务器找到(www. baidu. com)的主机。
可以通过dig命令查看域名解析的记录
dig www.baidu.com
; <<>> DiG 9.10.6 <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46850
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.baidu.com. IN A
;; ANSWER SECTION:
www.baidu.com. 98 IN A 163.177.151.109
www.baidu.com. 98 IN A 163.177.151.110
;; Query time: 7 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
;; WHEN: Tue Nov 12 19:51:36 CST 2019
;; MSG SIZE rcvd: 63
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
第一部分:显示 dig 命令的版本和输入的参数。
第二部分:显示服务返回的一些技术详情,当status 的值为 NOERROR 则说明本次查询成功结束。
第三部分: "QUESTION SECTION" 显示我们要查询的域名。
第四部分: "ANSWER SECTION" 是查询到的结果,返回该网址的2个IP。98为TTL的值,表示该域名的缓存时间,即该时间内不用重新查询。A是该DNS查询的记录类型,表示返回一个IPv4格式的地址。还有其他记录类型诸如 NS(返回查询的服务器地址)、AAAA(返回IPV6格式的地址)、CNAME(域名的别名)等
- NS 记录(域名服务) ─ 指定解析域名或子域名的 DNS 服务器。
- MX 记录(邮件交换) ─ 指定接收信息的邮件服务器。
- A 记录(地址) ─ 指定域名对应的 IPv4 地址记录。
- AAAA 记录(地址) ─ 指定域名对应的 IPv6 地址记录。
- NAME(规范) ─ 一个域名映射到另一个域名或 CNAME 记录( baidu. com 指向 www. baidu. com )或映射到一个 A记录。
- PTR 记录(反向记录) ─ PTR 记录用于定义与 IP 地址相关联的名称。 PTR 记录是 A 或 AAAA 记录的逆。 PTR 记录是唯一的,因为它们以 . arpa 根开始并被委派给 IP 地址的所有者
第五部分:本次查询的一些统计信息,Query time用了多长时间,SERVER查询了哪个 DNS 服务器,WHEN在什么时间进行的查询,MSG SIZE信息大小。
# 7. 缓存并返回结果
查找到目标ip后返回给本地DNS,本地DNS缓存该域名和相应id后将解析结果返回给用户,并缓存在操作系统中。域名解析过程至此结束
# 查询方式
![解析过程](/img/browser/查询方式. png)
# 递归查询
递归查询是一种DNS 服务器的查询模式,在该模式下DNS 服务器接收到客户机请求,必须使用一个准确的查询结果回复客户机。
如果DNS 服务器本地没有存储查询DNS信息,那么本地服务器就会成为DNS中的一台客户机,并向上级域名服务器发出查询请求,这种过程将持续到找到具有相关信息的域名服务器为止,然后将返回的查询结果提交给客户机。过程中如果没有找到查询结果,重复递归上述操作直至根域名服务器,根域名服务器收到DNS请求后,把所查询得到的所请求的DNS域名中发送给顶级域名服务器,让顶级域名服务器去往下级域名服务器请求查找,如果找到了就原路返回。
某域名服务器-->... ->顶级域名服务器-->根域名服务器-->下一级域名服务器-->... -->本地域名服务器-->客户机。如果没有找到就报错,表示无法查询到相关信息。
# 迭代查询
DNS 服务器会向客户机提供其他能够解析查询请求的DNS 服务器地址,当客户机发送查询请求时,DNS 服务器并不直接回复查询结果,而是告诉客户机另一台DNS 服务器地址,客户机再向这台DNS 服务器提交请求,依次循环直到返回查询的结果为止。迭代解析只是帮你找到相关的服务器而已,而不会帮你去查。
# 递归查询和迭代查询的区别
区别点/查询方式 | 递归查询 | 迭代查询 |
---|---|---|
工作方式 | 该DNS服务器按照DNS结构逐级查找结果 | 该DNS服务器找到相关服务器,让相关的服务器去查询结果 |
使用场景 | 从请求主机到本地DNS服务器的查询,一般发生在客户端与服务器间 | 根域名服务器 |
查询状态 | 在域名服务器查询期间,客户机将完全处于等待状态 | 直到服务器给出的提示中包含所需要查询的主机地址为止 |
# 预加载
通过使用预加载来缓解页面加载压力。DNS预解析实现预先域名解析的功能,加速服务器域名,调用资源直接通过解析后的 IP 不需要再进行 DNS 解析。
# DNS 预解析 dns-prefetch
通过指定具体的URL来告知客户端未来会用到相关的资源,这样浏览器可以尽早的解析DNS。现代浏览器帮我们做了很多,比如谷歌其实默认会对页面里已有的超链接做DNS预解析,我们DNS预解析的使用场景为预判:
- js可能发起的请求或跳转
- 用户可能重定向访问的页面
- 当静态资源和HTML不在一个域上,而在CDN上
- 超链接不用做,因为chrome或自动做dns prefetch
// 打开和关闭DNS预读取,X-DNS-Prefetch-Control头控制着浏览器的DNS预解析功能
<
meta http - equiv = "x-dns-prefetch-control"
content = "off" >
// 强制查询特定主机名
<
link rel = "dns-prefetch"
href = "https://www.baidu.com" >
2
3
4
5
6
7
8
dns-prefetch需慎用,多页面重复DNS预解析会增加重复DNS查询次数
浏览器支持:
– Safari: 5+
– Chrome: All
– Firefox: 3. 5+
– Opera: Unknown
– IE: 9+ (called “Pre-resolution” on blogs. msdn. com)
# DNS预解析一般方案
普通页面进行预加载的通用方案
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="x-dns-prefetch-control" content="off">
<link rel="dns-prefetch" href="">
<link rel="stylesheet" href="">
</head>
<body>
<script type="text/javascript">
(function() {
window.onload = function() {
var i = 0,
max = 0,
preloadJs = [
'js文件路径',
...
];
for (i = 0, max = preloadJs.length; i < max; i += 1) {
new Image().src = preloadJs[i];
}
};
})();
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 预连接 preconnect
与DNS prefetch类似,preconnect不光会解析DNS,还会建立TCP握手连接和TLS协议(https时),也就意味着存在更多开销,时间更慢。可以预先建立 socket 连接,从而消除昂贵的 DNS 查找、TCP 握手和 TLS 往返开销。
preconnect会占用CPU资源,如果该域名在10s内不会被使用到,不应该使用preconnect不需要缓存的请求数据,我们可以尝试实现preconnect
< link rel = "preconnect"
href = "https://www.baidu.com" >
2
# prefetch/preload
我们会在页面中使用 <link rel= preload >
& <link rel= prefetch >
来进行预加载。Webpack 4. 6. 0为我们提供了预先拉取(prefetching)和预先加载(preloading)的功能。使用这些声明可以修改浏览器处理异步chunk的方式。
# prefetch预先拉取
使用预先拉取,你表示该模块可能以后会用到。prefetch在浏览器会在空闲时间下载该模块,且下载是发生在父级chunk加载完成之后。预获取对 webfonts 性能提升非常明显。
import(
`./util/common`
/* webpackPrefetch: true */
/* webpackChunkName: "util" */
)
2
3
4
5
6
7
8
以上的导入会让 <link rel="prefetch" as="script" href="common.js">
被添加至页面的头部。因此浏览器会在空闲时间预先拉取该文件。
# preload预先加载
在资源上添加预先加载的注释,你指明该模块需要立即被使用。异步chunk会和父级chunk并行加载。如果父级chunk先下载好,页面就已可显示了,同时等待异步chunk的下载。当这能大幅提升性能。
Preload用于更早地发现资源并避免发起类似瀑布一样的请求。 它可以将页面加载降低到2次往返(1. HTML,2。所有其他资源),使用它不会花费额外的带宽。
import(
`./util/common`
/* webpackPreload: true */
/* webpackChunkName: "util" */
)
2
3
4
5
6
7
8
9
以上代码的效果是让 <link rel="preload" as="script" href="common.js">
起作用。不当地使用wepback的Preload会损害性能,所以使用的时候要小心。
# 去除内置prefetch/preload
webpack打包中会加入带有preload/preload的资源,使用该代码可以去除
chainWebpack(config) {
config.plugins.delete('preload')
config.plugins.delete('prefetch')
}
2
3
4
# preload和prefetch区别
preload块与父块并行加载。prefetch块会在父块加载结束后开始加载。
preload块具有中等优先级,并立即下载。prefetch块在浏览器闲置时下载
preload块会在父块中立即请求,用于当下时刻。prefetch块会用于未来的某个时刻
浏览器支持程度不同,preload支持情况约为50%,prefetch支持情况约为71%
# preload和prefetch缺点
在资源没有缓存的情况下使用 preload 或 prefetch,会造成用户带宽的浪费。未用到的 preload 资源在 Chrome 的 console 里会在 onload 事件 3s 后发生警告。
# 优化
DNS解析是很耗时,当解析域名过多时会让首屏加载变得过慢。优化的方法就是减少DNS查询。
合理减少页面的唯一域名
每次 DNS 查询就是查找唯一域名的过程,那么域名越少,DNS 查询就越少,应该尽量将资源放在同一域名。
dns-prefetch
让浏览器空闲时提前解析dns域名。当静态资源和HTML不在一个域上而在CDN上时,或者在重定向前可使用该方法。
# 参考
预加载小结待完善。