浏览器架构演进

身为常与浏览器共舞的Web工程师,尤其是Frontend Engineer,如果有一天浏览器突然消失了,应该要就地转行了吧?。
不过你知道浏览器为什么会变得越来越强呢?透过这篇文章,我想浅浅得介绍下浏览器的架构演进史。
身为Web工程师,浏览器与我们密不可分。但除了学会使用它以外,如果能去理解背后的运作模式,我认为是百利而无一害的。除了学会根据背后运作模式去建构更好的web应用以外,也可以提早洞察到未来可能的发展,领先其他人一步去探索更多可能性。
进程(process)/线程(thread)是两个必备的知识点,如果还不太了解两者概念的读者可以参考我之前的文章

单进程浏览器

在2007年之前,市面上的浏览器基本都是单进程(Single Process)单一程序架构的,即浏览器的网络线程、渲染线程、js环境等都是运行在同一个浏览器进程里面。

这样的架构存在下面几个问题:

  • 不稳定:某一线程崩溃(特别是第三方插件和JS环境),都会导致整个进程崩溃,最终就是整个浏览器崩溃。
  • 不安全:线程之间都是共享系统资源,所以导致插件或者JS脚本可能获取到浏览器隐私数据,造成信息安全,关键无法防护。
  • 不流畅:同一时刻只能运行一个线程,某一线程如果出现死循环(比如JS环境),则整个浏览器处于卡死状态。

以上就是单进程浏览器的最大缺陷,单进程架构下的浏览器只是达到了能用,但并不好用。

你能想象在你写完了长篇博文,还没来得及提交,就因为你去另一个页面点击了下一曲,导致整个浏览器崩溃,而导致你的努力全部白费的痛苦么?

多进程浏览器

自从chrome发布后,IE就被扫进了垃圾堆。那么原因是什么?能让消费者用脚投票让谷歌干翻微软,甚至Edge也直接使用chromium内核。

这是一张早期chrome架构图:

可以看到,chrome把最容易引起问题的两个模块独立成了单独进程,完美解决了单进程浏览器的问题。

  • 不稳定问题:让插件、渲染进程相互隔离,当一个页面的插件或者渲染崩溃时,影响的仅仅是当前页面的进程或者插件进程,并不影响其它页面。
  • 不安全问题:因为进程独立,插件和渲染进程无法相互访问数据,并通过因为沙盒(Sandbox)机制,使得插件和渲染进程访问系统数据受到了严格限制,即使存在恶意代码,也无法透过沙盒影响外部。
  • 不流畅问题:这种架构下,每个页面的渲染都是在独立的进程下,任何页面的渲染瓶颈也只能影响自身页面;而且通过多进程还可以最大化利用CPU多核性能,进一步提高了流畅度。

chrome仅仅通过架构上的调整,就解决了单进程浏览器的致命问题,现在看IE被扫进垃圾堆里一点都不冤。

但多进程也不是银弹,作为代价不可避免的带来了一些新的问题:

  • 更高的资源占用:因为每个进程都有独立的系统资源,这就意味着多进程浏览器相对于单进程浏览器会消耗更多的资源(比如内存)。
  • 更复杂的架构:浏览器各模块之间耦合性高、扩展性差等问题,会导致现在的架构已经很难适应新的需求了。

面向未来的浏览器

在 2016 年,Chrome 官方团队使用“面向服务的架构”(Services Oriented Architecture,简称 SOA)的思想设计了新的 Chrome 架构。也就是说 Chrome 整体架构会朝向现代操作系统所采用的“面向服务的架构” 方向发展,原来的各种模块会被重构成独立的服务(Service),每个服务(Service)都可以在独立的进程中运行,访问服务(Service)必须使用定义好的接口,通过 IPC 来通信,从而构建一个更内聚、松耦合、易于维护和扩展的系统,更好实现 Chrome 简单、稳定、高速、安全的目标。Chrome 最终要把 UI、数据库、文件、设备、网络等模块重构为基础服务,类似操作系统底层服务。

虽然说是面向面来,但 Chrome 团队已经在逐步往这套架构演进,为什么这么说,接着往下看。不过虽然 Chrome 已经开始改造了,但是现阶段仍处于迭代过渡的截断。

当前的多进程浏览器

以下内容完全基于chrome浏览器

在开始之前,我们一起看下,Chrome打开一个页面需要启动多少进程?

你可以点击Chrome浏览器右上角的“选项”菜单,选择“更多工具”,点击“任务管理器”,这将打开Chrome的任务管理器的窗口,如下图:

哇!好多进程!!!但通过观察,其实主要分为以下几类进程:

  • 浏览器进程:主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。
  • 渲染进程:核心任务是将HTML、CSS和JavaScript转换为用户可以与之交互的网页,排版引擎Blink和JavaScript引擎V8都是运行在该进程中,默认情况下,Chrome会为每个Tab标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。
  • GPU进程:Chrome刚开始发布的时候是没有GPU进程的。而GPU的使用初衷是为了实现3D CSS的效果,只是随后网页、Chrome的 UI 界面都选择采用GPU来绘制,这使得GPU成为浏览器普遍的需求。最后,Chrome在其多进程架构上也引入了GPU进程。
  • 插件进程:主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响。
  • Network Service:主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。
  • Audio Service:主要用于处理音频。
  • Storage Service:主要用于处理本地数据存储,包括Storage、Cache

为什么仍会出现某个页面崩溃导致其它页面一起崩溃的情况?

按照前面的说法,每个页面都有自己独立的功能模块进程,但是为什么还是会出现一个页面崩溃导致其它页面跟着崩溃的情况?这里就要引出 Chrome 的渲染进程策略了。

默认情况下,每个标签对应一个渲染进程,但是如果从当前页面打开了新的页面,而新的页面又与当前页面属于同一站点的话,那么 Chrome 就会复用当前页面的渲染进程。

如果新的页面跟当前页面不属于同一站点,那么新的页面就会产生新的渲染进程。

因此,当多个页面属于同一站点,共享一个渲染进程,当某个页面崩溃的时候,也将导致同一站点的其他页面也崩溃。这也就是 Chrome 任务管理器下会出现某些页面没有资源使用情况的原因。

总结

  • 单进程浏览器实现了人们对 Web 访问的需求,但是架构上先天存在不稳定不流畅不安全的问题。
  • 多进程浏览器的出现终结了单进程浏览器,但是也导致了更高的资源占用更复杂的架构体系等问题。
  • SOA是面向未来的浏览器架构,目的是构建一个高内聚低耦合易于维护和扩展的系统,现已逐步实现。