前面小节已经提到,打开一个网页,其中 80% 的时间被网络延迟占去了。
前面可以看到服务器响应时间仅是总延迟时间的 20%,其它都被 DNS,握手等操作占用了。过去用户体验研究( user experience research )表明用户对延迟时间的不同反应:
上表同样适用于页面的性能表现:渲染页面,至少要在 250ms 内给个回应来吸引住用户。这就是简单地针对速度。从 Google, Amazon, Microsoft,以及其它数千个站点来看,额外的延迟直接影响页面表现:流畅的页面会吸引更多的浏览、以及更强的用户吸引力(engagement) 和页面转换率(conversion rates).
现在我们知道了理想的延迟时间是 250ms,而前面的示例告诉我们,DNS Lookup, TCP 和 SSL 握手,以及 request 的准备时间花去了 370ms, 即便不考虑服务器处理时间,我们也超出了 50%。
对于绝大多数的用户和网页开发者来说,DNS, TCP,以及 SSL 延迟都是透明,很少有人会想到它。这也就是为什么 Chrome 的网络模块那么的复杂。
我们已经识别出了问题,下面让我们深入一下实现的细节。
关于多进程架构
Chrome 的多进程架构为浏览器的网络请求处理带来了重要意义,它目前支持四种不同的执行模式( four different execution models ).
默认情况下,桌面的 Chrome 浏览器使用 process- per-site 模式, 将不同的网站页面隔离起来, 相同网站的页面组织在一起。举个简单的例子: 每个 tab 独立一个进程。从网络性能的角度上说,并没什么本质上的不同,只是 process-per- tabl 模式更易于理解。
每一个 tab 有一个渲染进程(render process),其中包括了用于解析页面(interpreting)和排版(layout out)的 WebKit 的排版引擎(layout engine), 即上图中的 HTML Render。还有 V8 引擎和两者之间的 DOM Bindings,如果你对这部分很好奇,可以看这里( great introduction to the plumbing )。
每一个这样的渲染进程被运行在一个沙箱环境中,只会对用户的电脑环境做极有限的访问–包括网络。而使用这些资源,每一个渲染进程必须和浏览内核 进程(browser[kernel] process)沟通,以管理每个渲染进程的安全性和访问策略(access policies)。
渲染进程和内核进程之间的通讯是通过 IPC 完成的。在 Linux 和 Mac OS 上,使用了一个提供异步命名管道通讯方式的 socketpair ()。每一个渲染进程的消息会被序列化地到一个专用的I/O线程中,然后再由它发到内核进程。在接收端,内核进程提供一个过滤接口(filter interface)用于解析资源相关的 IPC 请求( ResourceMessageFilter ), 这部分就是网络模块负责的。
这样做其中一个好处是所有的资源请求都由I/O进程处理,无论是 UI 产生的活动,或者网络事件触发的交互。在内核进程(browser/kernel process)的I/O线程解析资源请求消息,将转发到一个 ResourceDispatcherHost 的单例(singleton)对象中处理。
这个单例接口允许浏览器控制每个渲染进程对网络的访问,也能达到有效和一致的资源共享:
项目还在增加中。
单就一个渲染进程而言,透过 IPC 发送资源请求很容易,只要告诉浏览器内核进程一个唯一 ID,后面就交给内核进程处理了。
现代魔法 推荐于 2013-02-27 10:23