DNS 预解析是什么?怎么实现?
DNS优化
在介绍dns-prefetch
之前,先要提下当前对于DNS优化主流方法。
一般来说,一次DNS解析需要耗费 20-120ms,所以为了优化DNS,我们可以考虑两个方向:
- 减少DNS请求次数
- 缩短DNS解析时间
dns-prefetch
什么是dns-prefetch?
dns-prefetch
(DNS预获取)是前端网络性能优化的一种措施。它根据浏览器定义的规则,提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,进而提高网站的访问速度。
为什么要用dns-prefetch?
每当浏览器从(第三方)服务器发送一次请求时,都要先通过DNS解析将该跨域域名解析为 IP地址,然后浏览器才能发出请求。
如果某一时间内,有多个请求都发送给同一个服务器,那么DNS解析会多次并且重复触发。这样会导致整体的网页加载有延迟的情况。
我们知道,虽然DNS解析占用不了多大带宽,但是它会产生很高的延迟,尤其是对于移动网络会更为明显。
因此,为了减少DNS解析产生的延迟,我们可以通过dns-prefetch
预解析技术有效地缩短DNS解析时间。
<link rel="dns-prefetch" href="https://baidu.com/">
dns-prefetch背后原理
当浏览器访问一个域名的时候,需要解析一次DNS,获得对应域名的ip地址。
在解析过程中,按照:
- 浏览器缓存
- 系统缓存
- 路由器缓存
- ISP(运营商)DNS缓存
- 根域名服务器
- 顶级域名服务器
- 主域名服务器
的顺序逐步读取缓存,直到拿到IP地址。
dns-prefetch
就是在将解析后的IP缓存在系统中。
这样,dns-prefetch
就有效地缩短了DNS解析时间。因为,在本地操作系统做了DNS缓存,使得DNS在解析的过程中,提前在系统缓存中找到了对应IP。
这样一来, 后续的解析步骤就不用执行了,进而也就缩短了DNS解析时间。
假如浏览器首次将一个域名解析为IP地址,并缓存至操作系统,那么下一次DNS解析时间可以低至0-1ms。
倘若结果不缓存在系统,那么就需要读取路由器的缓存,进而后续的解析时间最小也要约15ms。
如果路由器缓存也不存在,则需要读取ISP(运营商)DNS缓存,一般像taobao.com
、baidu.com
这些常见的域名,读取ISP(运营商)DNS缓存需要的时间在80-120ms,如果是不常见的域名,平均需要200-300ms。
一般来说,大部分的网站到运营商这块都能找到IP。
那也就是说,dns-prefetch
可以给DNS解析过程带来15-300ms的提升,尤其是一些大量引用很多其他域名资源的网站,提升效果就更加明显了
浏览器DNS缓存与dns-prefetch
现代浏览器为了优化DNS解析,也设有了浏览器DNS缓存。
每当在首次DNS解析后会对其IP进行缓存。至于缓存时长,每种浏览器都不一样,比如Chrome的过期时间是1分钟,在这个期限内不会重新请求DNS。
Tip:
每当Chrome浏览器启动的时候,就会自动的快速解析浏览器最近一次启动时记录的前10个域名。所以经常访问的网址就不存在DNS解析的延迟,进而打开速度更快。
而dns-prefetch
相当于在浏览器缓存之后,在本地操作系统中做了DNS缓存,个人理解,为的是给浏览器缓存做保障,尽量让DNS解析出本地,以此来做了又一层DNS解析优化。
一般来说,DNS在系统的缓存时间是大于浏览器的。
浏览器与系统DNS缓存时间
TTL(Time-To-Live),就是一条域名解析记录在DNS服务器中的存留时间
国内和国际上很多平台的TTL值都是以秒为单位的,很多的默认值都是3600,也就是默认缓存1小时。
dns-prefetch
缺点
dns-prefetch
最大的缺点就是使用它太多。
过多的预获取会导致过量的DNS解析,对网络是一种负担。
最佳实践
请记住以下三点:
dns-prefetch
仅对跨域域上的 DNS查找有效,因此请避免使用它来指向相同域。这是因为,到浏览器看到提示时,您站点域背后的IP已经被解析。
除了link 还可以通过使用 HTTP链接字段将 dns-prefetch
(以及其他资源提示)指定为 HTTP标头:
Link: <https://fonts.gstatic.com/>; rel=dns-prefetch
- 考虑将
dns-prefetch
与 preconnect(
预连接)
提示配对。
由于dns-prefetch
仅执行 DNS查找,不像preconnect
会建立与服务器的连接。
如果站点是通过HTTPS服务的,两者的组合会涵盖DNS解析,建立TCP连接以及执行TLS握手。将两者结合起来可提供进一步减少跨域请求的感知延迟的机会。如下所示:
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin>
<link rel="dns-prefetch" href="https://fonts.gstatic.com/">
Note: 如果页面需要建立与许多第三方域的连接,则将它们预先连接会适得其反。 preconnect
提示最好仅用于最关键的连接。对于其他的,只需使用 <link rel="dns-prefetch">
即可节省第一步的时间DNS查找。