Chrome浏览器架构

这篇文章,我们来讨论一下 Chrome 浏览器的架构。在讲架构之前,我们先来巩固一下两个概念:线程和进程。

进程和线程

先来看看进程。简单来讲一个进程就是一个程序的运行实例。具体来讲,就是启动一个程序的时候,操作系统会为该程序创建一块内存,用来存放代码、运行中的数据和一个执行任务的主线程,我们把这样的一个运行环境叫进程。

一个进程里可以有多个线程。线程不能单独存在,它是依附于进程的,并由进程启动和管理。多个线程之间可以共享进程中的数据,它们可以对进程里的公共数据进行读写操作。同时,只要有一个线程崩溃,那么整个进程就会崩溃。

当一个进程关闭后,操作系统会回收这个进程所申请的所有资源。

线程和进程的关系如下图:

了解完进程和线程之后,我们先来看看,远古时期的浏览器架构是什么样的。

单进程浏览器

在大约十几年前,浏览器还是单进程的结构。比如 IE6,IE6是单标签的,就是一个页面一个窗口。它把所有功能模块都运行在同一个进程里,这些模块包含了网络、插件、JS引擎和渲染引擎等。

这么多功能模块运行在一个进程里显然是不稳定的。这种架构下就会出现,一个浏览器中,其中一个页面或者插件卡死,整个浏览器都崩溃了。所以单进程浏览器会有这么几个明显的问题:不稳定、不流畅、不安全。

多进程浏览器

由于单进程浏览器存在诸多问题,之后就随之出现了多进程架构的浏览器。那么多进程架构是如何解决单进程架构问题的呢?

早期多进程架构

这个是早期 Chrome 的进程架构图。它主要包含这几个进程:浏览器主进程、渲染进程、插件进程。各个进程之间通过 IPC 机制通信。

因为进程和进程之间是相互隔离的,所以当一个页面或插件崩溃的时候,影响到的仅仅是当前的页面进程或者插件进程,并不会影响到其他页面。这样就完美的解决了不稳定的问题。

我们再来看看,卡顿的问题是如何解决的。首先在多进程浏览器中,每新打开一个页面都会为其新建一个渲染进程。同样,JS也是运行在渲染进程中的,所以即便是JS阻塞了渲染进程,它影响的也只是当前的页面,不会影响到其他页面。

关于JS脚本导致的内存泄露问题。当关闭这个页面时,这个进程所占用的所有内存会被系统回收,所以根本不存在内存泄漏的问题。

最后我们再来看看安全问题是怎么解决的。多进程浏览器的额外好处就是可以使用沙箱,你可以把沙箱看成是操作系统给进程上了一把锁,沙箱里面的程序可以运行,但是不能在你的硬盘上读写数据。我们可以从这个图中看出来, Chrome 把对外的插件进程和渲染进程锁在沙箱里,这样即使渲染进程或者插件进程里有恶意程序,也无法突破沙箱的限制去获取系统权限。

目前多进程架构

Chrome 的更新迭代非常迅速。相比之前,目前的架构又有了很多新的变化。那么我们来看看最新的Chrome 进程架构是什么样的。

从图中可以看出,现在的 Chrome 架构中包括下面几个进程:

  • 1个浏览器主进程
  • 1个GPU进程
  • 1个网络进程
  • 多个渲染进程
  • 多个插件进程

首先最重要的就是浏览器主进程。它主要负责界面展示、用户交互、子进程管理,同时提供存储等功能。

渲染进程的核心任务是将 HTML、CSS 和 JS 转换为用户可以与之交互的网页。渲染引擎 Blink 和 V8 都是运行在该进程中。在默认情况下,chrome会为每个 Tab 页创建一个渲染进程,出于安全考虑,渲染进程都是运行在沙箱模式下的。

GPU进程。开始 Chrome 是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果。后来网页、Chrome 的 UI 界面都选择采用 GPU 绘制,这样使 GPU 成为浏览器的一个普遍需求。最后,Chrome 在架构上引入了 GPU 进程。

网络进程,主要负责页面的网络资源加载。以前它是作为一个模块运行在主进程里的,现在把它独立出来,成为一个单独的进程。

插件进程主要是负责插件的运行,因为插件容易崩溃,所以用进程来隔离插件出现的问题是一个很好的方案。

我们可以通过 Chrome 里的任务管理器来查看当前运行的进程。那么打开一个页面,至少需要 4个进程:1个浏览器进程、1个网络进程、1渲染进程、1个 GPU 进程,如果有插件的话,还有一些插件进程。

上图中还有一个进程:V8 代理解析工具,它是干什么用的呢?Chrome 支持使用 JavaScript 来写连接代理服务器脚本,又称为在线 PAC 代理脚本,使用 PAC 代理脚本可以实现一些会被请去喝茶的事情。刚开始的时候,Chrome 是在浏览器进程里面解析 PAC 代理脚本的,由于是 JavaScript脚 本,所有需要在浏览器进程里面引入 V8,不过把 V8 运行在浏览器进程似乎不太好,于是 Chrome 团队后来就把这个功能独立出来一个进程了,这个进程就叫“Utility: V8 Proxy Resolver”。

不过凡事都有两面性,虽然多进程模型提升了浏览器的稳定性、流畅性和安全性,但同样不可避免地带来了一些问题:

  • 更高的资源占用。因为每个进程都会包含公共基础结构的副本(如 JavaScript 运行环境),这就意味着浏览器会消耗更多的内存资源。
  • 更复杂的体系架构。浏览器各模块之间耦合性高、扩展性差等问题,会导致现在的架构已经很难适应新的需求了。

未来面向服务的架构

对于这些问题,Chrome 团队一直在寻求一种弹性方案。在2016年,Chrome 团队使用了“面向服务的架构”(Services Oriented Architecture,简称 SOA)的思想设计了新的 Chrome 架构。

也就是说 Chrome 最终要把 UI、数据库、文件、设备、网络等模块重构为基础服务,类似操作系统底层服务,下面是 Chrome“面向服务的架构”的进程模型图:Chrome 整体架构会朝向现在操作系统所采用的“面试服务的架构”方向发展,原来的各种模块会被重构成独立的服务(Service),每个服务(Service)都可以在独立的进程中运行。从而构建一个更内聚、松耦合、易于维护和扩展的系统,更好实现 Chrome 简单、稳定、高速、安全的目标。

Chrome 最终要把 UI、数据库、文件、设备、网络等模块重构为基础服务,类似操作系统底层服务,下面是 Chrome“ 面向服务的架构”的进程模型图:

目前 Chrome 正处在老的架构向服务化架构过渡阶段,这将是一个漫长的迭代过程。Chrome 正在逐步构建 Chrome 基础服务(Chrome Foundation Service),如果你认为 Chrome 是“便携式操作系统”,那么 Chrome 基础服务便可以被视为该操作系统的“基础”系统服务层。

同时 Chrome 还提供灵活的弹性架构,在强大性能设备上会以多进程的方式运行基础服务,但是如果在资源受限的设备上(如下图),Chrome 会将很多服务整合到一个进程中,从而节省内存占用。

在资源不足的设备上,将服务合并到浏览器进程中

总体说来,Chrome 是以一个非常快速的速度在进化,越来越多的业务和应用都逐渐转至浏览器来开发。我们期待 Chrome 将来可以承托更多的业务场景,比如移动设备、VR、视频等。鉴于目前架构的复杂性,要完整过渡到面向服务架构,估计还需要好几年时间才能完成。不过 Chrome 开发是一个渐进的过程,新的特性会一点点加入进来,这也意味着我们随时能看到 Chrome 新的变化。