Cover

未来的操作系统基于数据库?

Wenxuan Shi /
February 10, 2022
21 min read

计算机领域有很多延续至今的「习惯」,或者说「规定」。例如冯诺依曼结构,内存堆栈模型,QWERT 键盘。有些习惯在今天看起来毫无道理。比如键盘的 QWERT 排列,据说是为了降低金属打字机中相邻按键的粘滞几率而设计的。随着工艺的进步,粘滞已经不再出现,但这种排列被当做习惯保留了下来。

作为科研人,我们要经常审视那些习以为常的东西 —— 它们对于当下是否仍然有贡献?有没有更高效的解决方案?秉持着这样的态度,有一批科研人员就盯上了计算机领域最常见、最广泛、最习以为常的基础设施 —— 操作系统。他们要用新的操作系统取代云服务器上的 Unix/Linux。而且,这个操作系统竟然是基于数据库的!

他们的畅想发表在这篇 VLDB-2021 会议文章里,题目为《DBOS: a DBMS-oriented operating system》。文章的作者来自 Stanford,MIT,Google 和 VMWare。顺便查了一下作者中的中国人李芊,本科北大、硕士斯坦福,目前斯坦福博士在读。

Unix/Linux 与流行技术概念的脱节

随着计算机和互联网技术的发展,大型系统的开发获得了越来越广泛的关注。作者总结了当下系统方向的流行技术概念:超大规模、云服务、并行计算、专用计算单元(与 GPU,TPU,FPGA 进行交互,完成数据计算)、新应用场景(例如机器学习、物联网、大数据)、新编程模型(例如 Serverless 兴起后的微服务模型)、证据采集(公证、司法取证,或利用数据进行漏洞分析)。

面对这些流行技术概念时,Unix/Linux 因为几个关键的缺点,而在潜在的竞争中处于劣势。

一、缺乏集群支持

经典的观点认为:集群支持由上层应用完成,操作系统负责管理本机的资源。目前行业内广泛使用的 Kubernetes 和 Slurm 就是用于进行集群编排与管理的应用。

等一等,为什么操作系统要支持多机集群?

操作系统的定义是 “管理硬件与软件资源的程序”,一台机器是硬件,多台机器就不能称为硬件吗?

作者的观点是:正是因为把多机管理交给了上层应用完成,才导致了目前工业实践中严重的割裂问题。在上层应用与底层内核之间存在巨大的抽象隔阂(Abstraction Gap),使得取证、监控、安全加固、漏洞排查等操作的实现面临挑战。目前的工业实践中,经常针对特定应用额外定制方案,缺乏广泛性。如果由操作系统来完成这部分工作,会使得未来的云服务变得更加灵活,更加可靠。

二、性能累赘与功能冗余

为了性能或更加细致的控制,越来越多的开发者选择使用内核旁路(Kernel Bypass)的方式进行硬件操作。所谓内核旁路,即是绕过内核直接在用户空间进程使用硬件。这足以印证 Linux 内核的性能表现不佳。

从行业发展前景看,未来的云服务一定是 Serverless 的天下。Serverless 需要的运行时(runtime)比操作系统提供的复杂抽象简单得多。比如,Serverless 运行时不需要 Demand page 这种为节约物理内存页而设计的功能。

未来操作系统

🧐

Rethinking the OS

读到这里,大致可以对作者设想的未来操作系统有一个概念性的构想:操作系统管理一整个集群,集群中包含若干节点(由 CPU、内存、异质硬件组成的基础计算单元)。在这个系统中运行的不是线程、进程,而是 Serverless 函数。

想要理解作者眼中的未来操作系统,必须先打破固有认知。操作系统不一定是每台计算机所独有的,而可以是一组计算机所共有的。操作系统的定义是 “管理硬件与软件资源的程序”。如果把多个计算机绑定成为一个集群,它们可以共同被一个操作系统所管理。

既然单机软硬件资源的管理权利被集中到了上层,那就没必要在单机上运行 Unix/Linux 了。其原因有二:一是 Unix/Linux 无法绝对服从上层管理进行线程调度。二是它们有很多冗余的成分。

在作者的设计中,单机(节点)上运行微型内核(Micro Kernel)。微型内核只提供基础的硬件资源抽象(初级设备处理、中断处理、简单的节点间通信),舍弃了硬件及软件资源的管理能力。

作者总结道:归根结底,Unix/Linux 系统的抽象能力要么太少,要么太底层,不能很好的管理现代系统中大量繁杂的状态。其根本原因是 Unix 在 1973 年采用的 “万物皆文件” 的模型,是为单核处理器的资源管理创建的。这个模型在多核机器乃至多节点集群中,应当升级为 “万物皆表”。

把 Unix/Linux 批判一番后,作者终于搬出了自己的解决思路:基于数据库管理系统(DBMS)做一个操作系统!

DBOS:基于数据库系统的操作系统

随着系统中状态数的增加,操作系统的资源管理问题逐渐演变成了大数据问题。因此需要在内核中嵌入一个现代的、高效的、多节点的事务型数据库管理系统。

可以说是脑洞大开了。系统方向的研究者尽各种努力都是想让内核模块化、轻量化,而作者直接整合了一个数据库进去。不慌,我们来看看这个操作系统的设计。

第四层:用户态应用

在 DBOS 里运行的用户态应用主要是分布式应用(Distributed Applications),应用场景主要是机器学习、网页搜索、并行分析、APP 后端等。这些应用必须满足作者规定的 Serverless 计算模型:将任务分割成子任务图,每个子任务占用一段较短的时间。子任务在运行前必须声明自己所占用的内存大小。 运行子任务前,去数据表里查询节点的剩余内存情况。如果某个节点的剩余内存足够塞下子任务,那就放进这个节点执行。

更方便的 IPC

在一般的 Serverless 服务中,数据的共享是由共享对象存储或文件系统来完成的。这是因为任务分布在集群的角角落落,很难找到进程间通信(IPC)的接受者。在 DBOS 里,所有的系统状态都被规范地写在表里。所以进程间通信可以通过数据表完成。顺带获得了数据库的同步原语。

更方便的状态监控

在 DBOS 中,所有系统状态全部存储在数据表中,可以直接用 SQL 语句提取出来。例如寻找某一应用的所有进程 ID,某一应用目前的内存占用,或者任何自定义的聚合指标。甚至所有 IPC 通信都在存放在表中,可以直接按时间顺序提取出来做分析。

第三层:操作系统功能层

DBOS 的第三层以 SQL 和用户定义的函数组成,基于数据库实现任务调度、分布式文件系统、IPC 通信等等操作系统的功能。

经典操作系统中,获取系统各个部分的指标需要使用各种专用的 API,且缺乏一致性。与经典操作系统不同,DBOS 的系统功能以一致的全局视角观察或修改系统状态。

这些功能基于数据库固然是方便,不过是否会影响性能?

性能是这篇文章中实验的重点。通过在 VoltDB 上构建一个 PoC,作者证明了可以用分布式数据库实现这些功能,甚至获得了媲美单机服务的性能。使用数据表实现的 MQ/IPC 服务,某些场景下性能超过了 gRPC。基于数据表的文件系统写入速度超过了 EXT4。

第二层:分布式数据库系统

支撑操作系统功能的是一个高性能、多节点、主内存、事务型的分布式数据库。在处理分布式事务上,数据库延迟低、拥有并发控制和冲突恢复。通过实时故障转移实现高可用。

第一层:微内核

我们前文已经阐述过,作者希望在单机上运行一个微内核服务,提供初级设备处理、中断处理,以及简单的节点间通信功能。

讨论:数据库 - 操作系统,前途无量还是前途无亮?

我赞同作者开篇的观点:现有的 Unix/Linux 确实是太陈旧了,性能差、维护难、设计略显混乱,依靠开源社区缝缝补补二十多年。操作系统的思想需要一次革新。

总体来说,这篇论文很适合像我这样的新手读:结构的设计很 trivial,但是故事讲的很漂亮。读完之后的讨论空间也很大,甚至能让我水一篇博客。 😂

本文的主要贡献是什么?

其一是提出使用规范的查询语言 SQL 进行系统状态的管理。

Unix/Linux 使用很多特殊的数据结构管理自身状态,其中不少还非常 tricky。这些结构隐藏在大大小小的模块中,需要调用各种 API 才能获得。DBOS 提出将系统状态放到数据库中,使用数据表维护。这个方案是很漂亮的。正如我们前文讲到的,它消除了抽象隔阂(Abstraction Gap)。而且能更方便地进行取证、监控、安全加固、漏洞排查工作。

我自己的感想是:规范的状态管理对提升安全性也有帮助。甚至对于完成形式化证明都有帮助:系统状态的查询与修改始终通过全局的统一接口完成。无论程序逻辑如何复杂,最终会落实到一条 SQL 语句。而 SQL 语句本身就是形式化的,背后有关系代数的支撑。

其二是将操作系统的状态空间放大到数据中心的维度。

集群的管理一直受到各种限制,我们都同意是集群管理层和操作系统层的整合(intergration)不完全。但作者直接指明,在操作系统上运行集群管理程序的「金字塔结构」是一个既不工整、又不经济的方案。

长久以来,操作系统负责对资源进行抽象和管理。这篇文章里暗示抽象和管理是两件可以解耦的事情。虽然作者忘记把这点明确写出来,但这个思路在大型数据中心里是很畅销的。单节点微内核负责抽象,多节点分布式系统负责管理。操作系统所 “操作” 的不是单一硬件,而是一整个中心的硬件。

其三是证明数据库系统的性能可以媲美 Unix/Linux 内核。

通过在 VoltDB 上构建一个 PoC,作者证明了可以用分布式数据库提供诸如 IPC、任务调度、文件系统的服务。这些服务甚至获得了媲美单机服务的性能。使用数据表实现的 MQ/IPC 服务,某些场景下性能超过了 gRPC。基于数据表的文件系统写入速度超过了 EXT4。

这些成果离不开数据库领域长久的研究和发展。一直是数据库领域的先锋们在探索低延迟、高并发、冲突恢复、实时故障转移的数据存取方案。云服务时代,这些探索回过头遇见了操作系统,一鸣惊人般地能和内核一较高低。

DBOS 存在哪些问题?

但是作者的拿出的设计又是 trivial 的,甚至是 childish 的。文中用数据库实现了操作系统的三个功能:文件系统、任务调度、进程间通信。距离一个真正的操作系统还差的很远。

性能问题仍然需要担忧。IPC 只是超过了 gRPC,但是比原生 TCP/IP 通信慢了不少。基于数据库实现的文件系统在小文件读写场景里超过了 EXT4,可能作者忘记把大文件读写的测试结果写进文章。我把这篇论文分享给朋友们看,得到最多的反馈就是:如果 DBOS 能提供和 Linux 一样的功能性,那它的性能还有这么好吗?

此外,我期待看到的诸如 I/O 管理、页表的实现、内存堆栈模型文中都没有涉及。甚至作者直接明说不做动态内存管理,而是强制要求子任务在运行前声明自己所占用的内存大小。

🤨

这个假设合理吗

看起来 DBOS 没有动态内存管理功能(比如定义页表、处理缺页中断、处理碎片化问题等等),而是依赖一个假设:所有的子任务都提前声明占用内存的大小。

无论是复杂的应用程序,还是普通的一个函数,运行时内存占用很难在编译期确定。

首先面临的是面向对象中「多态」派发的挑战:即抽象类型的子类实例占用的内存空间无法确定。尤其是当抽象类型作为函数参数传递时,由于不确定参数的内存大小,必须使用动态派发。动态派发又引入了额外的语言运行时进行类型检查,而语言运行时又会引入额外的内存占用……

也许我们可以尝试让编译器统计内存占用。用户的输入仍然会极大影响程序的内存占用。想象这段程序:它把用户输入的正则表达式编译成状态机,再进行文本匹配。即使用户输入长度是有限的(例如至多 255 个字符),状态机的具体内存占用也无法在编译期确定。

如果不去确定准确的内存大小,而是去推测一个 upper bound 作为分配的依据呢?同样的问题:编译器无法在有限时间里分析得到占用内存的上界。例如,某程序每执行一步就往数组末尾添加一比特。如果编译期能确定这个程序的内存上界,那必须先解决停机问题,这意味着证明 P=NP。

最后,我们只能要求程序员对自己写的函数负责。即对于无法确定内存上界的函数,由开发者自行定义函数的最大内存占用。超过声明的内存占用将直接返回错误。为了防止程序员把数值设置得过大而影响其他函数的执行,云平台可以根据内存占用进行阶梯型收费。从而倒逼程序员写出更 Serverless 的代码。

但是我们要求不能太高。毕竟做数据库和做系统之间还是有 gap。你不能要求一个研究数据库的老师来开操作系统课,他大概率是讲不好的。

© LICENSED UNDER CC BY-NC-SA 4.0

Subscribe to the blog via RSS