DNS(Domain Name System),翻译为域名解析系统,是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。
围绕DNS可做的性能优化非常的多,比如大家所熟知的全局负载均衡(GSLB),用户可以访问到离自己最近服务器,从而获得最优的访问体验,这项优化更多需要服务端去完成。前端主要关注 DNS Prefetch。
DNS Prefetch原理
当浏览器访问一个域名的时候,需要解析一次DNS,获得对应域名的ip地址。在解析过程中,按照浏览器缓存、系统缓存、路由器缓存、ISP(运营商)DNS缓存、根域名服务器、顶级域名服务器、主域名服务器的顺序,逐步读取缓存,直到拿到IP地址。
DNS Prefetch,即DNS预解析就是根据浏览器定义的规则,提前解析之后可能会用到的域名,使解析结果缓存到系统缓存中,缩短DNS解析时间,来提高网站的访问速度。
如果页面之前访问了,我们可以从浏览器的DNS缓存当中直接读取。减少了解析时间,以及请求次数。
打开DNS Prefetch之后,浏览器会在空闲时间提前将这些域名转化为对应的IP地址,这里为了防止DNS Prefetch阻塞页面渲染影响用户体验,Chrome浏览器的引擎并没有使用它的网络堆栈去进行预解析,而是单独开了8个完全异步的Worker线程专门负责DNS Prefetch。所以很多人认为的DNS Prefetch会影响首屏加载其实是错误的,两者并没有任何关系,所以我们可以大胆放心的使用DNS Prefetch。
如何使用
浏览器自动解析
浏览器引擎在解析HTML页面的时候,会自动获取当前页面所有的a标签herf属性当中的域名,然后进行 DNS Prefetch。这个解析过程是与用户浏览网页并行处理的。但是为了确保安全性,在HTTPS页面中没有开启 DNS Prefetch。
1 | // 开启DNS Prefetch |
手动解析
1 | <link rel="dns-prefetch" href="//jkfhto.github.io"> |
1 | DNS Prefetch解析后的域名对应关系会缓存到本地,一般本地缓存的数量为50~200个 |
正确的使用姿势
- 在整个站点的入口声明DNS预解析。通过在站点入口声明了后续其他子页面和子站点可能会访问的域名,浏览器提前进行了DNS预解析。这样用户在访问其他子站点的时候将会间接受益于入口的预解析,降低了DNS lookup所消耗的时间。
- 根据实际情况配置当前页面的DNS预解析。声明后续操作可能会用到的域名,如发送的异步请求、动态加载图片等等。
- 并不是DNS prefetch设置的越多越好,虽然是异步线程,实际上还是占用设备的带宽,造成资源竞争。
- 借助开发者工具,对静态资源域名做手动dns prefetching。
- 如果是HTTPS网页,考虑是否需要对超链接自动解析,如果需要,添加对应的meta标签。
- 检查js中发起的跳转至其他域名的情况,对于这些域名,做手动dns prefetching。
- 对重定向跳转的新域名做手动dns prefetching。比如:页面上有个A域名的链接,但访问A会重定向到B域名的链接,这么在当前页对B域名做手动dns prefetching是有意义的。
解决的问题及收益
DNS Prefetch有效缩短了DNS的解析时间。
如果浏览器最近将一个域名解析为IP地址,所属的操作系统将会缓存,下一次DNS解析时间可以低至0-1ms。 如果结果不在系统本地缓存,则需要读取路由器的缓存,则解析时间的最小值大约为15ms。如果路由器缓存也不存在,则需要读取ISP(运营商)DNS缓存,一般像taobao.com、baidu.com这些常见的域名,读取ISP(运营商)DNS缓存需要的时间在80-120ms,如果是不常见的域名,平均需要200-300ms。一般的网站在运营商这里都能查询的到,所以普遍来说DNS Prefetch可以给一个域名的DNS解析过程带来15-300ms的提升,尤其是一些大量引用很多其他域名资源的网站,提升效果就更加明显了。
Chromium对底层缓存进行了建模,当Chrome浏览器启动的时候,就会自动的快速解析浏览器最近一次启动时记录的前10个域名。所以你经常访问的网址就没有DNS解析的延迟,打开速度更快。