多域名线程并发与 DNS 预解析

军训结束, 感想不多, 就一句话

【这就是个无限循环,每天重复训练一套动作,直到结束为止,毫无意义】

回家之后我帮父母看店, 顺便点开了浏览器, 浏览器卡死了 30s, 终于完全加载出了一个花花绿绿的主页, 是大名鼎鼎的 2345 主页.

虽然我很反感这种杂七杂八的傻逼导航, 我也试图将主页换成 magi 或 dogedoge, 但是父亲就很不习惯, 原因很难以接受:

儿子啊,这样我怎么看天气啊。

。。。

于是我顺手右键点开了源代码,闲着无聊看看,结果却刚看看就找到了好 看的东西:

<link rel="dns-prefetch" href="https://union2.50bang.org">
<link rel="dns-prefetch" href="//h.2345cdn.net">
<link rel="dns-prefetch" href="//image.2345.com">
<link rel="dns-prefetch" href="//00imgmini.eastday.com">
<link rel="dns-prefetch" href="//01imgmini.eastday.com">
<link rel="dns-prefetch" href="//02imgmini.eastday.com">
<link rel="dns-prefetch" href="//03imgmini.eastday.com">
<link rel="dns-prefetch" href="//04imgmini.eastday.com">
<link rel="dns-prefetch" href="//05imgmini.eastday.com">
<link rel="dns-prefetch" href="//pos.baidu.com">
<link rel="dns-prefetch" href="//p.tanx.com">
<link rel="dns-prefetch" href="//gma.alicdn.com">

欸,dns-prefetch 是什么?

好吧,看起来你我都不懂.

多并发请求

请问,一号网页和二号网页哪个加载更快?

假设每张图片的大小为无限小, 传输速度为无限大,exmple1.comexmple.com 的镜像

一号:

<!doctype html>
<html>
<body>
<img src="https://exmple.com/1.jpg">
<img src="https://exmple.com/2.jpg">
<img src="https://exmple.com/3.jpg">
<img src="https://exmple.com/4.jpg">
<img src="https://exmple.com/5.jpg">
<img src="https://exmple.com/6.jpg">
<img src="https://exmple.com/7.jpg">
<img src="https://exmple.com/8.jpg">
<img src="https://exmple.com/9.jpg">
<img src="https://exmple.com/10.jpg">
<img src="https://exmple.com/11.jpg">
<img src="https://exmple.com/12.jpg">
</body></html>

二号:

<!doctype html>
<html>
<body>
<img src="https://exmple.com/1.jpg">
<img src="https://exmple.com/2.jpg">
<img src="https://exmple.com/3.jpg">
<img src="https://exmple.com/4.jpg">
<img src="https://exmple.com/5.jpg">
<img src="https://exmple.com/6.jpg">
<img src="https://exmple1.com/7.jpg">
<img src="https://exmple1.com/8.jpg">
<img src="https://exmple1.com/9.jpg">
<img src="https://exmple1.com/10.jpg">
<img src="https://exmple1.com/11.jpg">
<img src="https://exmple1.com/12.jpg">
</body></html>

好了公布答案了, 很显然 号加载更快。

这时候有人就会问了,凭什么啊!不是说图片无限小吗?右边的反而会增加 dns 解析时间,难道不会更慢吗?

好吧好吧,实际上,你以为的加载时间是这样的

可是实际上是这样子的:

欸这就很有意思了同学们,为什么最后六张会出现 Pending 状态?

实际上,浏览器是有并发请求数目限制【通常是 2-8 个】,虽然这种比较坑人,但这也是为了避免同时大量并发导致资源占用过度,并且只针对同一个域名的(例如向 cdn.jsdelivr.net 发送请求)。即一时间针对同一域名下的请求有一定数量限制。超过限制数目的请求会被阻塞并进入 Pending 状态。

从用户的角度来说,浏览器不可能无限量的并发请求,因此衍生出来了并发限制和 HTTP/1.1 的 Keep alive。 所以,IE6/7 在 HTTP/1.1 下的并发才 2,但 HTTP/1.0 却是4。 而随着技术的发展,负载均衡和各类 NoSQL 的大量应用,基本已经足以应对 C10K 的问题。 但却并不是每个网站都懂得利用 domain hash 也就是多域名来加速访问。因此,新的浏览器加大了并发数的限制,但却仍控制在 8 以内。

然而从服务器的角度来讲,我们也可以窥见,无限制的并发请求无异于一次小型 CC,对于保护服务器和优化用户体验还是相当重要的。

从网站上入手,实际上这一点相当容易理解,2345 一打开就是少则五十多张图片同时加载, 甚至那些下拉箭头为了兼容 ie 都还是图片而非 fontawesome, 如果不绕过并发限制, 岂不是一片空白.

那么问题来了,如何避免堵塞?

答案显然易见, 多换几个域名不就行了?? 这样图片分别从两个域名获取,直接避免恼火的 Pending,

2345 主页中 00imgmini.eastday.com05imgmini.eastday.com 五个域名均是拿来绕开并发限制的。

每请求一次资源,就会生成一次新的 Cookie。如果网站每个资源 cookie 有 1 KB、网站首页共 150 个资源时,用户在请求过程中需要发送 150 KB 的 cookie 信息,在 512 Kbps 的常见上行带宽下,需要长达 3 秒左右才能全部发送完毕。 尽管这个过程可以和页面下载不同资源的时间并发,但毕竟对速度造成了影响。 而且这些信息在 js/css/images/html 等静态资源上,几乎是没有任何必要的。

解决方案是启用和主站不同的域名来放置静态资源,也就是 cookie free。

注意此处所指的是主域名而非子域名,子域名的 Cookie 会和主域名共存

但是这样,就孪生出一个极其严重的问题,多个域名,必然会加重 DNS 解析时间SSL 的握手时间

避免 DNS 拥堵

一旦采用 多域名的方式绕开并发量限制 ,就会导致浏览器在请求时必须一个一个解析过去,从00imgmini.eastday.com05imgmini.eastday.com,然而 DNS 解析时间虽然短,但是多个解析必然导致严重拖慢速度,此时我们就需要进行预解析。

请注意,预解析在部分主流浏览器中支持,但是并不是所有页面和条件下都支持。

正常情况下打开一个网页,浏览器会做出以下动作:

  1. 浏览器向请求网址发起 DNS 解析

  2. 浏览器向服务器一个 GET 请求,拉起进入 Pending

  3. 浏览器解析 html,完成初步 CSS 渲染【此时标题栏显示标题】

  4. 进行 js 解析,并请求额外的资源

DNS 解析时间的浪费主要阻塞在第四步,为避免解析时间的阻塞,我们采用dns-prefetch 进行优化.

在 html 头添加

<meta http-equiv="x-dns-prefetch-control" content="on" />

向浏览器表明我需要预解析。

接着【建议】在<meta charset="UTF-8"> 后添加

<link rel="dns-prefetch" href="//exmple.com">
<link rel="dns-prefetch" href="//exmple1.com">

表明强制解析这些域名。并且以后会一直记住这个域名的解析结果直到关闭为止。

// 开始是为了适配 httpshttp 。就是当前请求链接是 https ,那么这个 // 前面自动补充 https ,反则补充 http 。

建议

切记 dns-prefetch 不能滥用,它虽然能一定提升网页打开速度,但也会对浏览器产生一定负担。

这边的建议是,作为个人,我并不推荐将此方法运用于个人博客。原因很简单,你博客一次能有几张图片?如果你是开图站的,那么这个方法刚好可以运用到你的网站里,只要进行多域名分开并 dns 欲解析就可以进一步提升网站体验了。

最后上生肉:

DNS prefetching is an attempt to resolve domain names before a user tries to follow a link. This is done using the computer’s normal DNS resolution mechanism; no connection to Google is used. Once a domain name has been resolved, if the user does navigate to that domain, there will be no effective delay due to DNS resolution time. The most obvious example where DNS prefetching can help is when a user is looking at a page with many links to various domains, such as a search results page. When we encounter hyperlinks in pages, we extract the domain name from each one and resolving each domain to an IP address. All this work is done in parallel with the user’s reading of the page, using minimal CPU and network resources. When a user clicks on any of these pre-resolved names, they will on average save about 200 milliseconds in their navigation (assuming the user hadn’t already visited the domain recently). More importantly than the average savings, users won’t tend to experience the “worst case” delays for DNS resolution, which are regularly over 1 second.


 目录