Google Chrome中的高性能网络(二)

Chrome Predictor的预测功能优化

Chrome会随着使用变得更快。 它这个特性是通过一个单例对象Predictor来实现的。这个对象在浏览器内核进程(Browser Kernel Process)中实例化,它唯一的职责就是观察和学习当前网络活动方式,提前预估用户下一步的操作。下面是一个示例:

  • 用户将鼠标停留在一个链接上,就预示着一个用户的偏好以及下一步的浏览行为。这时Chrome就可以提前进行DNS Lookup及TCP握手。用户的点击操作平均需要将近200ms,在这个时间就可能处理完DNS和TCP相关的操作, 也就是省去几百毫秒的延迟时间。
  • 当在地址栏(Omnibox/URL bar) 触发高可能性选项时,就同样会触发一个DNS lookup和TCP预连接(pre-connect),甚至在一个不可见的页签中进行预渲染(pre-render)!
  • 我们每个人都一串天天会访问的网站, Chrome会研究在这些页面上的子资源, 并且尝试进行预解析(pre-resolve), 甚至可能会进行预加载(pre-fetch)以优化浏览体验。

除了上面三项,还有很多..

Chrome会在你使用过程中学习Web的拓扑结构,而不单单是你的浏览模式。理想的话,它将为你省去数百毫秒的延迟, 更接近于即时页面加载的状态. 正是为了这个目标,Chrome投入了以下的核心优化技术:

DNS预解析(pre-resolve) 提前解析主机地址,以减少DNS延迟
TCP预连接(pre-connect) 提前连接到目标服务器,以减少TCP握手延迟
资源预加载(prefetching) 提前加载页面的核心资源,以加载页面显示
页面预渲染(prerendering)     提前获取整个页面和相关子资源,这样可以做到及时显示

每一个决策都包含着一个或多个的优化, 用来克服大量的限制因素.  不过毕竟都只是预测性的优化策略,如果效果不理想,就会引入多余的处理和网络传输。甚至可能会带来一些加载时间上的负体验。

Chrome如何处理这些问题呢? Predictor会尽量收集各种信息,诸如用户操作,历史浏览数据,以及来自渲染引擎(render)和网络模块自身的信息。

和Chrome中负责网络事务调度的ResourceDispatcherHost不同,Predictor对象会针对用户和网络事务创建一组过滤器(filter):

  • IPC channel filter用来监控来自render进程的事务。
  • 每个请求上都会加一个ConnectInterceptor 对象,这样就可以跟踪网络传输的模式以及每一个请求的度量数据。

渲染进程(render process)会在一系列的事件下发送消息到浏览器进程(browser process), 这些事件被定义在一个枚举(ResolutionMotivation)中以便于使用 (url_info.h):

enum ResolutionMotivation {
  MOUSE_OVER_MOTIVATED,     // 鼠标悬停.
  OMNIBOX_MOTIVATED,        // Omni-box建议进行解析.
  STARTUP_LIST_MOTIVATED,   // 这是在前10个启动项中的资源.
  EARLY_LOAD_MOTIVATED,     // 有时需要使用prefetched来提前建立连接.

  // 下面定义了预加载评估的方式,会由一个navigation变量指定.
  // referring_url_也需要同时指定.
  STATIC_REFERAL_MOTIVATED,  // 外部数据库(External Database)建议进行解析。
  LEARNED_REFERAL_MOTIVATED, // 前一次浏览(prior navigation建议进行解析.
  SELF_REFERAL_MOTIVATED,    // 猜测下一个连接是不是需要进行解析.

  // <略> ...
};

通过这些给定的事件,Predictor的目标就可以评估它成功的可能性, 然后再适时触发操作。每一项事件都有其成功的机率、优先级以及时间戳,这些可以在内部维护一个用优先级管理的队列,也是优化的一个手段。最终,对于这个队列中发出的每一个请求的成功率,都可以被Predictor追踪到。基于这些数据,Predictor就可以进一步优化它的决策。

Chrome网络架构小结

  • Chrome使用多进程架构,将渲染进程同浏览器进程隔离开来。
  • Chrome维护着一个资源分发器的实例(a single instance of the resource dispatcher), 它运行在浏览器内核进程,并在各个渲染进程间共享。
  • 网络层是跨平台的,大部分情况下以单进程库存在。
  • 网络层使用非阻塞式(no-blocking)操作来管理所有网络任务。
  • 共享的网络层支持有效的资源排序、复用、并为浏览器提供在多进程间进行全局优化的能力。
  • 每一个渲染进程通过IPC和资源分发器(resource dispatcher)通讯。
  • 资源分发器(Resource dispatcher)通过自定义的IPC Filter解析资源请求。
  • Predictor在解析资源请求和响应网络事务中学习,并对后续的网络请求进行优化。
  • Predictor会根据学习到的网络事务模式预测性的进行DNS解析, TCP握手,甚至是资源请求,为用户实际操作时节省数百毫秒的时间。

了解晦涩的内部细节后,让我们来看一下用户可以感受到的优化。一切从全新的Chrome开始。

优化冷启动(Cold-Boot)体验 

第一次启动浏览器,它当然不可能了解你的使用习惯和喜欢的页面。但事实上,我们大多数会在浏览器的冷启动后做些类似的事情,比如到电子邮箱查看邮件,加一些新闻页面、社交页面及内部页面到我的最爱,诸如此类。这些页面各有不同,但它们仍然具有一些相似性,所以Predictor仍然可以对这个过程提速。

Chrome记下了用户在全新启动浏览器时最常用的10个域名。当浏览器启动时,Chrome会提前对这些域名进行DNS预解析。你可以在Chrome中使用chrome://dns查看到这个列表。在打开页面的最上面的表格中会列出启动时的备选域名列表。

通过Omnibox优化与用户的交互


引入Omnibox是Chrome的一项创新, 并不是简单地处理目标的URL。除了记录之前访问过的页面URL,它还与搜索引擎的整合,并且支持在历史记录中进行全文搜索(比如,直接输入页面名称)。

当用户输入时,Omnibox自动发起一个行为,要么查找浏览记录中的URL, 要么进行一次搜索。每一次发起的操作都会被加以评分,以统计它的性能。你可以在Chrome输入chrome://predictors来观察这些数据。


Chrome维护着一个历史记录,内容包括用户输入的前置文字,采用的行为,以命中的资数。 在上面的列表,你可以看到,当输入g时,有76%的机会尝试打开Gmail. 如果再补充一个m (就是gm), 打开Gmail的可能性增加到99.8%。

那么网络模块会做什么呢?上表中的黄色和绿色对于ResourceDispatcher非常重要。如果有一个一般可能性的页面(黄色), Chrome就是发起DNS预解析。如果有一个高可能性的页面(绿色),Chrome还会在DNS解析后发起TCP预连接。如果这两项都完成了,用户仍然继续录入,Chrome就会在一个隐藏的页签进行预渲染(pre-render)。

相对的,如果输入的前置文字找不到合适的匹配项目,Chrome会向搜索引擎服务者发起DNS预解析和TCP预连,以获取相似的搜索结果。

平均而言用户从填写查询内容到评估给出的建议需要花费数百毫秒。 此时Chrome可以在后台进行预解析,预连接,甚至进行预渲染。再当用户准备按下回车键时,大量的网络延迟已经被提前处理掉了。

优化缓存性能 

最快的请求就是没有请求。 无论何时讨论性能,都不能不谈缓存。相信你已经为页面上所有资源的都提供了Expires, ETag, Last-Modified和Cache-Control这些响应头信息(response headers)什么? 还没有?那你还是先处理好再来看吧!

Chrome有两种不同的内部缓存的实现:一种备份于本地磁盘(local disk),另一种则存储于内存(in-memory)中。内存模式(in-memory)主要应用于无痕浏览模式(Incognito browsing mode),并在关闭窗口清除掉。 两种方式使用了相同的内部接口(disk_cache::Backend, 和disk_cache::Entry),大大简化了系统架构。如果你想实现一个自己的缓存算法,可以很容易地实现进去。

在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里。其中有索引文件(在浏览器启动时加载到内存中),数据文件(存储着实际数据,以及HTTP头以及其它信息)。比较有趣的是,16KB以下的文件存储于共同的数据块文件中(data block-files,即小文件集中存储于一个大文件中),其它较大的文件才会存储到自己专属的文件中。最后,磁盘缓存的淘汰策略是维护一个LRU,通过比如访问频率和资源的使用时间(age)的度量进行管理。

在Chrome开个页签,输入chrome://net-internals/#httpCache。 如果你要看到实际的HTTP数据和缓存的响应处理,可以打开chrome://cache, 里面会列出所有缓存中可用的资源。打开每一项,还可以看到详细的数据头等信息。

优化DNS预解析

前面已经多次提到了DNS预解析,在深入实现之前,先汇总一下DNS预解析的场景和理由:

  • 运行在渲染进程中的WebKit文档解析器(document parser), 会为当前页面上所有的链接提供一个主机名(hostname)列表,Chrome可以选择是否提前解析。
  • 当用户要打开页面时,渲染进程先会触发一个鼠标悬停(hover)或按键(button down)事件。
  • Omnibox可能会针对一个高可能性的建议页面发起解析请求。
  • Chrome Predictor会基于过往浏览记录和资源请求数据发起主机解析请求。(下面会详细解释。)
  • 页面本身会显式地要求Chrome对某些主机名称进行预解析。

上述各项对于Chrome都只是一个线索。 Chrome并不保证预解析一定会被执行,所有的线索会由Predictor进行评估,以决定后续的操作。最坏的情况下,可能无法及时解析主机名,用户就必须等待一个DNS解析时间,然后是TCP连接时间,最后是资源加载时间。Predictor会记下这个场景,在未来决策时相应地加以参考。总之,一定是越用越快。

之前提过到Chrome可以记住每个页面的拓扑(topology),并可以基于这个信息进行加速。还记得吧,平均每个页面带有88个资源,分别来自于30多个独立的主机。每打开这个页面,Chrome会记下资源中比较常用的主机名,在后续的浏览过程中,Chrome就会发起针对某些主机或者全部主机的DNS解析,甚至是TCP预连接!

 


使用chrome://dns 就可以观察到上面的数据(Google+页面), 其中有6个子资源对应的主机名,并记录了DNS预解析发生的次数,TCP预连接发生的次数,以及到每个主机的请求次数。这些数据就可以让Chrome Predictor执行相应的优化决策。

除了内部事件通知外,页面设计者可以在页面中嵌入如下的语句请求浏览器进行预解析:

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

之所以有这个需求,一个典型的例子是重定向(redirects). Chrome本身没办法判断出这种模式,通过这种方式则可以让浏览器提前进行解析。

具体的实现也是因版本而有所差异,总体而言,Chrome中的DNS处理有两个主要的实现:1.基于历史数据(historically), 通过调用平台无关的getaddrinfo()系统函数实现。2.代理操作系统的DNS处理方法,这种方法正在被Chrome自行实现的一套异步DNS解析机制(asynchronous DNS resolver)所取代。

依赖于系统的实现,代码少而且简单,但是getaddrinfo()是一个阻塞式的系统调用,无法有效地并行多个查询操作。经验数据还显示,并行请求过多甚至会超出路由器的负额。Chrome为此设计了一个复杂的机制。对于其中带有worker-pool的预解析, Chrome只是简单的发送getaddrinfo() 调用, 同时阻塞worker thread直到收到响应数据。因为系统有DNS缓存的原因,针对解析过的主机,解析操作会立即返回。 这个过程简单,有效。

但还不够! getaddrinfo()隐藏了太多有用的信息,比如Time-to-live(TTL)时间戳, DNS缓存的状态等。于是Chrome决定自己实现一套跨平台的异步DNS解析器。


这个新技术可以支持以下优化:

  • 更好地控制重转的时机,有能力并行执行多个查询操作。
  • 清晰地记录TTLs。
  • 更好地处理IPv4和IPv6的兼容。
  • 基于RTT和其它事件,针对不同服务器进行错误处理(failover)

Chrome仍然进行着持续的优化. 通过chrome://histograms/DNS可以观察到DNS度量数据:

上面的柱状图展示了DNS预解析延迟时间的分布:比如将近50%(最右侧)的查询在20ms内完成。这些数据基于最近的浏览操作(采样9869次),用户可以选择是否报告这些使用数据,然后这些数据会以匿名的形式交由工程团队加以分析,这样就可以了解到功能的性能,以及未来如何进一步调整。周而复始,不断优化。

转载请注明出处:http://blog.csdn.net/horkychen
原文地址: http://www.igvita.com/posa/high-performance-networking-in-google-chrome/

from :http://blog.csdn.net/horkychen/article/details/10421523

时间: 2024-10-28 15:21:51

Google Chrome中的高性能网络(二)的相关文章

Google Chrome中的高性能网络 (三)

使用预连接优化了TCP连接管理 已经预解析到了主机名,也有了由OmniBox和Chrome Predictor提供信号,预示着用户未来的操作.为什么再进一步连接到目标主机,在用户真正发起请求前完成TCP握手呢?这样就可省掉了另一个往返的延迟,轻易地就能为用户节省到上百毫秒.其实,这就是TCP预连接的工作. 通过访问chrome://dns 就可以看到TCP预连接的使用情况. 首先, Chrome检查它的socket pool里有没有目标主机可以复用的socket, 这些sockets会在sock

frameset 在 Google Chrome 中无法隐藏左边栏解决方法!

使用Frameset 框架,发现在IE下, <frameset name="mainDefine" cols="200,10,*" frameborder="NO" border="0" framespacing="0" rows="*"> <frame name="LeftFrame" noresize scrolling="auto&q

转载:关于 Google Chrome 中的全屏模式和 APP 模式

前言:我一直在纠结这篇文章是否应该归类在「前段开发」的范围内,哈哈! 前段时间做了一个项目,涉及到一个要全屏模式去访问网页的需求,因为 Google Chrome 的效率不错,而且专门为 Chrome 做网页也省事许多,所以就在网上找如何让 Chrome 在允许的时候直接全屏模式.还以为会是 fullscreen 之类的参数,没想到参数名还挺偏的. 正巧最近和同事说到这个时,同事告诉我还有一个 APP 模式,也可以用来满足一些特殊需求,今晚都尝试了一下,两者之间有各自的用途,说说我的想法吧. 全

Ajax请求在IE和Google Chrome中可以响应,在Firefox中无法响应

在工作中碰到这么一个问题,发送ajax请求,在IE和chrome中可以正常的响应,但是在Firefox中无法响应,代码如下: JS代码: 1 function Sure(obj) { 2 var statu = confirm("是否确认删除?"); 3 if (!statu) { 4 return false; 5 } 6 var objOrderID = obj.id; 7 $.ajax( 8 { 9 type: "Post", 10 url: "/A

Google Chrome抓包分析详解

Google Chrome抓包分析详解 一:什么是抓包 即抓取我们本地电脑与远端服务器通信时候所传递的数据包 二:Chrome浏览器讲解 Chrome 开发者工具是一套内置于Google Chrome中的Web开发和调试工具,可用来对网站进行迭代.调试和分析 三:打开Chrome开发者工具 在Chrome界面按F12 or在页面元素上右键点击,选择“检查” 四:开发者工具的结构 Elements(元素面板):使用“元素”面板可以通过自由操纵DOM和CSS来重演您网站的布局和设计. Console

Chrome 中调试Javascript

使用Chrome打开我们要调试的页面,然后使用快捷键F12打开开发者工具,当然,你也可以在工具菜单中找到.Chrome开发者工具如图: Elements选项卡是对界面上的元素进行选择的,我们要进行调试的代码在Sources 选项卡中. 打开Sources选项卡,点击左侧的小箭头打开所有资源,选择我们的页面: 我们要调试这个页面的代码,所以就打开这个页面,然后点击行号可以添加断点: 点击界面中的按钮,我们能够捕获到刚添加的断点: 添加监视的方法和在IE中的方法是一样的:选中变量,在变量上面单击,选

在Chrome 中调试Javascript

在前面的两篇文章中我们讲了如何在IE中调试Javascript和在Visual Studio中调试Javascript,在本篇内容中,我们讲一下如何在谷歌 Chrome中调试Javascript. Chrome 是Google 提供的一款非常优秀的浏览器,内置了开发者工具,可以方便我们对JS代码进行调试.有了使用IE来调试Javascript的经验,在使用Chrome进行调试的时候会变得很方便. 使用Chrome打开我们要调试的页面,然后使用快捷键F12打开开发者工具,当然,你也可以在工具菜单中

在 Ubuntu 14.04 Chrome中安装Flash Player(转)

在 Ubuntu 14.04 中安装 Pepper Flash Player For Chromium 一个 Pepper Flash Player For Chromium 的安装器已经被 Ubuntu 14.04 的官方源收录. Flash Player For Linux 自11.2 起已经停止更新,目前 Linux 平台下面的 Flash Player 只能依靠 Google Chrom 的 PPAPI (Pepper Flash Player)进行更新(Chrome Only)(Ado

利用Google Chrome开发插件,在网页中植入js代码

Google Chrome是一个很强大的浏览器,提供了各种各样的插件,大大提升了使用了的效率,比如vimium.honx等. Google在提供这些插件的同时还允许用户开发自己的插件. 最近在写js的脚本采集程序,需要测试在网页中的运行情况,因此可以利用Chrome插件进行测试. 1.首先第一步是新建一个文件夹,并新建一个manifest.json文件,内容如下 { "manifest_version": 2, "name": "Js implants&q