anjia / blog

博客,积累与沉淀
107 stars 4 forks source link

Servo 的设计架构 #3

Open anjia opened 6 years ago

anjia commented 6 years ago
  • Quantum 初探:介绍了 Quantum 项目的由来和概况,也顺便介绍了 Servo 的小历史
  • Servo 的设计架构:即本篇文章,将介绍 Servo 的基于任务的设计架构,重点介绍并行并发的策略

Servo 的设计架构

对,我就是 Servo 的官方 Logo

Servo 是一款现代化的高性能浏览器引擎,既支持常规应用,也支持嵌入使用。官网 https://servo.org

她由 Mozilla 开发,由三星集团移植到 Android 系统和 ARM 处理器,旨在创造一个大规模并行计算的环境,Servo 也与 Rust 编程语言有着共生的关系。源自 https://zh.wikipedia.org/wiki/Servo

1. 设计简介

Servo 是一个新的 Web 浏览器引擎。她的目标是创建一个多层级的高并发架构,同时在架构层面消除与错误的内存管理、数据竞争相关的常见 bug 和安全漏洞。

因为 C++ 不适合处理这类问题,所以 Servo 是用 Rust 语言编写的。Rust 在设计的时候充分考虑了 Servo 的需求,它提供了任务并行的基础架构和强类型系统,从而保证了内存安全、避免了数据竞争。

在设计的时候,Servo 的架构师们会优先考虑现代 Web 平台的以下特性:高性能、动态、富媒体应用,可能会牺牲一些无法优化的特性。他们想知道一个快速响应的 Web 平台是什么样子的,然后再实现它。

Servo 专注于实现一个功能完备的 Web 浏览器引擎和可靠的嵌入式引擎,前者(Web 浏览器引擎)使用了基于 HTML 的用户界面 Browser.html。尽管 Servo 最初只是一个研究型项目,但在开发它的时候就以提供可用于生产环境的代码为目标。目前,Servo 的一些组件已经迁移到了 Firefox 浏览器。

关于集成到 Firefox 中的 Servo 组件,可查看 Jack Moffitt 的演讲视频 Web Engines Hackfest

并行并发的策略

并发是拆分任务以便交叉执行;并行是同时执行多个任务以提高速度。Servo 在以下环节中用到了并行和并发。

GC,Garbage Collection,垃圾回收

挑战

2. 任务架构

tasks-sup 图1. 任务监管图,源自 servo/wiki/Design

tasks-comm 图2. 任务通信图,源自 servo/wiki/Design

说明

我们可以把每个 constellation(见“附录.术语”小节)实例看做是浏览器的单个页签或者窗口,它管理着接收输入的任务管道,针对 DOM 运行 JavaScript,执行布局,构建显示列表,将显示列表渲染到瓦片上,最后把最终图像合成到屏幕上。

这个管道由四个主要任务组成:

管道中的多任务通信涉及到两种复杂的数据结构:DOM 和显示列表。DOM 从内容传到布局,显示列表从布局传到渲染。找出一种有效且类型安全的方式来表示、共享和传递这两种数据结构是该项目的诸多挑战之一。

写时复制 DOM

Servo 的 DOM 树节点是有版本控制的,它们可以在单个 writer 和多个 reader 之间共享。DOM 使用写时复制(copy-on-write)的策略允许当有多个 reader 时 writer 也能修改 DOM。writer 总是内容任务,reader 总是布局任务或其子任务。

DOM 节点是 Rust 值(Rust value),而 Rust 值的生命周期由 JavaScript 垃圾收集器管理。JavaScript 直接访问 DOM 节点,而没有依赖 XPCOM 或其它类似的基础设施。

DOM 接口目前不是类型安全的,这可能会导致不正确的节点管理。消除这类不安全是该项目的一个必要的高优先级目标;由于 DOM 节点具有复杂的生命周期,这将会带来一些挑战。

显示列表

Servo 的渲染完全由显示列表驱动,显示列表是由布局任务创建的一系列高级绘图命令。Servo 的显示列表是完全不可变的,因此它可以被同时运行的多个渲染任务所共享。这与 Webkit 和 Gecko 的渲染器不同:WebKit 的渲染器没有使用显示列表;Gecko 的渲染器使用了显示列表,但它在渲染期间还会查询额外的信息。

3. JavaScript 和 DOM 绑定

目前,Servo 使用的脚本引擎是 SpiderMonkey(可插拔引擎是一个长期的、低优先级的目标)。每个内容任务都有自己的 JavaScript 运行时。DOM 绑定使用原生的 JavaScript 引擎 API 而不是 XPCOM。从 WebIDL 自动生成绑定是一个高优任务。

4. 多进程架构

与 Chromium 和 WebKit2 类似,Servo 的架构师们打算做一个可信任的应用程序进程和多个不太可信的引擎进程。高级 API 实际上是基于 IPC 的,非 IPC 实现可能用于测试和单进程用例(虽然预计最糟糕的时候也会用于多进程)。引擎进程将使用操作系统沙箱工具来限制对系统资源的访问。

目前,Servo 并不打算像 Chromium 那样采用极端沙箱(extreme sandboxing),主要是因为锁定沙箱会导致大量的开发工作(特别是在 Windows XP 和旧版 Linux 等低优先级的平台上),并且该项目的其它方面的优先级更高一点。Rust 的类型系统还为内存安全漏洞增加了一层重要的防御功能,虽然仅凭这一点并不能使沙箱在防御不安全代码、类型系统中的错误以及第三方/主机库等方面变得不那么紧迫,但相对于其他浏览器引擎它确实能显著减少 Servo 的攻击面。此外,Servo 的架构师们对某些沙箱技术有性能方面的顾虑(例如,将所有 OpenGL 调用代理到单独的进程)。

5. I/O和资源管理

网页依赖于各种各样的外部资源,而这些资源具有很多的检索和解码机制。这些资源会被缓存在多处,比如磁盘、内存。在并行浏览器的设置中,这些资源一定会在并发的多个 worker 之间调度。

通常,浏览器是单线程的,会在“主线程”上执行 I/O,而“主线程”同时又担负着大部分的计算任务,这就会导致延迟问题。而 Servo 中没有“主线程”,所有外部资源的加载都由一个资源管理任务来处理。

浏览器有很多缓存,而 Servo 的基于任务的架构意味着它可能会拥有比现有浏览器引擎还多的缓存(例如,我们在拥有全局任务缓存的同时,也拥有着一个本地任务缓存,它存储着来自全局缓存的结果,以通过调度程序来保存往返记录)。Servo 应该有一个统一的缓存机制,以便在低内存的环境中也运行良好。

附录. 术语

小结

本文主要介绍了 Servo 的设计概况,重点介绍了它基于任务的整体架构及其四个主要任务(也称“线程”,在 Servo 的这个上下文里),即脚本任务、布局任务、渲染任务、合成任务。下图便是对上述内容的一个总结,希望对大家有所帮助和启发。

servo 图3. Servo 概况

下一步

后续,我会继续探索更多详细内容,敬请期待。关于 Quantum 和 Servo,如果您有其它更想知道的,欢迎留言。

致谢

感谢 @cncuckoo(李松峰老师)和 @liuguanyu(二哥)对本文提出的指导意见和建议。手动送花花。🌹

参考

cncuckoo commented 6 years ago

“Rust 是专门针对 Servo 的需求而设计的一种新的编程语言”,这个结论有出处吗? “从而保证了内存安全和数据竞争自由”——“数据竞争自由”,是不会出现“竞争读取数据”这种情况的意思?

anjia commented 6 years ago

@cncuckoo 有。https://github.com/servo/servo/wiki/Design 的第二段

Because C++ is poorly suited to preventing these problems, Servo is written in Rust, a new language designed specifically with Servo's requirements in mind. Rust provides a task-parallel infrastructure and a strong type system that enforces memory safety and data race freedom.


“从而保证了内存安全和数据竞争自由”——“数据竞争自由”,是不会出现“竞争读取数据”这种情况的意思?

确切地说,是不会出现多个线程同时不安全“写”的情况(当都同时“读”的时候,不构成竞争)。因为 Rust 可以让多个线程安全的并行,至于如何避免数据竞争,我还没深究 :) 。这里有篇文章 https://hacks.mozilla.org/2017/06/avoiding-race-conditions-in-sharedarraybuffers-with-atomics/#data-race

PS. 我把“数据竞争自由” 改成 “避免数据竞争”,感觉更好点~!

cncuckoo commented 6 years ago

Because C++ is poorly suited to preventing these problems, Servo is written in Rust, a new language designed specifically with Servo's requirements in mind.

这句话如果理解成:“Rust 是专门针对 Servo 的需求而设计的一种新的编程语言”,有点片面了。

我觉得理解成:“Rust在设计时充分考虑了Servo的需求”,可能更符合Rust作为一门通用系统语言的定位。

cncuckoo commented 6 years ago

“Servo 是一款现代化的高性能浏览器引擎,专为应用程序和嵌入式应用而设计。”

还有这句对官网的slogan的翻译,容易让人误解。后半句似乎翻译成:“既支持常规应用,也支持嵌入使用”更好。

anjia commented 6 years ago

@cncuckoo 李老师,已修正。更新后,意思确实更精准了,手动🌹

anjia commented 6 years ago

更多相关,详见 label:servo

wlex-club commented 4 years ago

“Rust 是专门针对 Servo 的需求而设计的一种新的编程语言” 这句话太片面了

anjia commented 4 years ago

“Rust 是专门针对 Servo 的需求而设计的一种新的编程语言” 这句话太片面了

@vle-william 嗯,这个是站在“起源”的角度说的。发展到现在,现在再这么说,是片面的。

zzz6519003 commented 4 years ago

并发是拆分任务以便交叉执行;并行是同时执行多个任务以提高速度??

anjia commented 4 years ago

并发是拆分任务以便交叉执行;并行是同时执行多个任务以提高速度??

@zzz6519003 嗯,是的。图解的话,大约如下:上-并发;下-并行。

并发并行

zzz6519003 commented 4 years ago

how sweet~