《WebKit技术内幕》知识提炼 —— 资源加载和网络栈

WebKit 资源加载机制

资源

HTML 支持的资源主要包括:HTML、JavaScript、CSS、图片、SVG、CSS Shader、视频、音频、字幕、字体、XSL样式表等

这些资源在 WebKit 中都有不同的类表示,公共基类是 CachedResource。其中 HTML文本的类型为 MainResource,对应的资源类型叫 CachedRawResource类。

资源缓存

基本思想是建立一个缓存池,优先从缓存池中读取数据。这里的所说的缓存池是内存缓存。WebKit 从资源池中查找资源的关键词是URL,只要URL不同,就被认为是两个不同的资源

资源加载器

分为三种:

  • 针对每种资源类型的特定加载器,仅加载某一种资源,并且没有公共基类,加载器属于它的调用者。如 ImageLoader 属于 HTMLImageElement
  • 缓存机制加载器 CachedResourceLoader 所有特定加载器都共享它来查找并插入缓存资源,属于 HTML 文档的对象
  • 通用资源加载器 ResourceLoader类,WebKit 需要从网络或者文件中获取资源的时候使用,只负责获取资源数据

过程

资源加载过程

例子:有一个 “img” 元素,“src”是一个有效 URL 地址,当 HTML 解释器解析到该元素的该属性,WebKit 会创建一个 ImageLoader 对象来加载该资源,ImageLoader创建一个缓存资源请求CachedResourceRequest,并调用CachedResourceLoader 查找缓存资源,如果命中缓存则返回给调用者,如果没有命中则创建一个资源请求ResourceRequest ,并且调用通用资源加载器加载资源,具体到下面的 ResourceHandleInternal ,依赖于每个 WebKit 移植的实现策略。

存在默写资源会阻塞主线程渲染过程,当前的主线程渲染被阻塞时,WebKit 会启动另外一个线程去遍历后面的 HTML 网页,收集需要的资源 URL,并可以并发下载这些资源。

资源的生命周期

资源池使用 LRU(Least Recently Used 最近最少使用)算法,并且在这个基础上添加了协商缓存。如果命中缓存,那么发送一个 HTTP 请求给服务器,说明资源在本地的一些信息,如资源更新时间,服务器根据信息判断,如果没有更新,则返回状态码 304,那么直接使用原资源;否则下载最新资源。

Chromium 多进程资源加载

Renderer 进程在网页的加载过程中需要获取资源,但由于安全性(沙箱模型打开的时候,Renderer进程是没有权限获取资源的)和效率上(资源可以共享),Renderer 进程的资源获取实际上是通过进程间通信将任务交给 Browser 进程来完成。

网络栈

WebKit 的资源加载的优化其实是交由各个移植来实现的,WebCore 没有什么也别的基础设施,每个移植的网络实现是非常不一样的。

网络栈的基本组成

除了 HTTP 协议、DNS 解析等,还包含了 Chromium 为了减少网络时间而引入的新技术,例如 SPDY,QUIC

网络栈结构
网络栈调用过程
  1. URLRequest 类被调用时,会根据 URL 的 “scheme”(协议类型,如:“http://”,“file://”等) 来决定要创建什么类型的请求,Chromium 使用工厂模式处理不同类型的请求,例如 “http://” 类型则会使用 URLRequestJobManager 创建一个 URLRequestJob 类,具体使用哪个工厂则是一个责任链模式,优先判断是否是用户自定义的 “scheme” 。
  2. URLRequestJob 被创建后,先从 Cookie 管理器中获取与该 URL 相关的信息,之后使用 HttpTransactionFactory 对象创建 HttpTransaction 对象开启一个 Http 连接的事务。如果请求对应的回复已经在磁盘缓存中,那么 Chromium 无需再建立 HttpTransaction
  3. HttpNetworkTransaction 使用 HttpNetworkSession 类来管理会话。通过 HttpStreamFactory 对象来建立 TCP Socket 连接。之后 HttpStreamFactory 创建 HttpStream 对象,来处理对象和网络之间数据的读写。
  4. Chromium 中与服务器建立连接的套接字是 SteamSocket 类,它是一个抽象类,再 POSIX 系统和 Windows 系统上有不同实现。
域名解析(DNS)

Chromium 使用 HostResolverImpl 类来解析域名,具体调用的是 “getaddrinfo()”,是一个阻塞式函数,所以使用单独的线程处理。为了考虑效率,使用 HostCache 类来保存解析后的域名,还有 DNS 预解析机制。

磁盘本地缓存

要求:

  • 要有相应的机制来移除合适的缓存资源
  • 浏览器崩溃时不破坏磁盘文件
  • 可以通过同步或异步的方式高效快速的访问
  • 避免同时存储相同的资源
  • 操作一个项的时候不受其他请求影响
  • 磁盘不支持多线程访问,磁盘的缓存操作要放到单独的线程
  • 支持老版结构

实现上主要有两个类,Backend(整个磁盘缓存) 和 Entry(表中的表项)。至少需要一个索引文件和四个数据文件。索引文件用来索引,数据文件又称块文件。

索引文件
包括一个索引头部和索引地址;头部用来表示该索引文件的信息(索引文件版本号、索引项数量、文件大小等信息);索引地址表保存各个表项对应的索引地址,直接将文件映射到内存地址。从内存地址可以找到数据文件,数据文件也是一个文件头加上后面的块文件,每个块的大小是固定的,当超过 512 字节的时候会为其分配多个块。但最多不超过四个,超过通常会用单独的文件存储。如果一个表项要分配四个块,那么是和块索引位置是对齐的(起始块的位置是4的倍数)

表项结构
分为两个部分,第一部分标记自己,包括元数据信息和自身内容。另一部分经常发生变动,主要为表项的回收算法服务,保存了回收算法所需的信息(LRU回收算法)。

高性能网络栈

DNS 预取和 TCP 预连接

一次 DNS 查询约 60~120ms,而 TCP 的三次握手也大约几十毫秒

DNS 预取:利用现有的 DNS 机制,提前解析网页中可能的连接。不是使用前面提到的 Chromium 网络栈,而是直接利用系统的域名解析机制,不会阻碍当前网络栈的工作,针对多个域名采取并行处理的方式,每个域名的解析由一个新线程处理,结束后退出。网页开发者可以显示指定哪些域名来让 Chromium 解析,使用方法:<link rel="dns-prefetch" href='"htttp://...">。 用户地址栏也同理。

TCP 预链接:使用追踪技术获取用户从什么网页跳转到另一个网页,利用这些数据、和一些启发规则来 DNS 预取和 TCP 预链接,这对用户隐私是一个巨大挑战。

HTTP 管线化

HTTP1.1 开始增加了管线化技术,可以将多个 HTTP 请求一次性提交给服务器,无需等待服务器回复,因为它可能将多个HTTP 请求填充在一个 TCP 数据包内。能在高延迟的链接环境下有明显的性能提升。

局限性:需要通过永久连接完成,并且只有 GET 和 HEAD 等请求可以进行管线化。

SPDY

为了解决网络延迟和安全问题,根据 Google 官方数据,可以将网络加载时间减少 64%,HTTP2.0 将引入 SPDY 协议,将其作为基础来编写。

SPDY

SPDY 协议是一种新的会话层协议,是一种栈式结构,被定义在 HTTP 协议和 TCP 协议之间,核心是多路复用,仅使用一个连接来传输一个网页中的众多资源。本质上并没有改变 HTTP 协议,只是将 HTTP 协议头通过 SPDY 来封装传输,数据传输方式也没有发生变化。所以比较容易部署,服务器只需要插入 SPDY 协议的解释层,从 SPDY 的消息头中获取各个资源的 HTTP 头即可。但 SPDY 必须建立在 SSL 层之上。

特征:

  • 利用一个 TCP 连接来传输不限个数的资源请求的读写数据流,提高 TCP 连接的利用率,减少 TCP 连接的维护成本
  • 可以调整这些资源请求的优先级
  • 对请求使用压缩技术
  • 可以尝试发送一些信息给浏览器,告诉浏览器后面可能需要哪些资源,更极端可以主动发送资源给浏览器。
QUIC

QUIC 是一种新的网络传输协议,目标是改进 UDP 数据协议的能力,解决传输层的传输效率,并提供数据的加密,SPDY 可以在 QUIC 上工作。

更多

《WebKit技术内幕》知识提炼 —— WebKit 架构和模块

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354