外行冒昧答一发。Midori的前身是研究项目Singularity, 从Joe Duffy的文章来看,基本设计还是一样的。Singularity: Rethinking the Software Stack - Microsoft Research 这篇文章应该还是了解 Midori的很好的切入点。一句话描述的话,它就是一个建立在managed语言之上的操作系统,抛开各种陈年假定,提出了新的隔离和并发模型,以及新的进程间通讯方式的一个操作系统。
这篇文章对我有特殊意义。我看到这篇文章的时候毕业不久在互联网后台搬砖研究C10K之类的问题 —— 现在大家都玩C100K了。这篇文章,正如标题,带我去想一个更本质,却又并不复杂的问题 —— 如果我们抛开所有历史包袱、既定事实,在现代硬件上重新设计一个软件技术体系,它应该是怎样的?这个问题本身为我打开了一个全新的世(nao)界(dong)。
比如,现在你在一个用户态C程序上要一段内存, 你至少得经过三层抽象:首先malloc会用一坨迷之策略在一个虚拟的连续地址空间给你分配一段地址,你去访问这个地址,可能会触发缺页中断,然后操作系统通过另一坨迷之策略给你找一个可用的物理内存页,然后改你的页表做虚存地址到物理地址映射。然后!你的指令到了CPU,MMU才根据页表把你指令中的地址转成物理内存地址去访问内存。虽然经过无数先烈的重重优化,这里的overhead还可以轻松占到整个运行时的10%以上,当然更恐怖的是你永远都说不准这个overhead — it all depends.
但是为什么要搞这么复杂?是因为要在多道程序环境给每个程序相互隔离的空间,不管怎么乱搞都不会搞挂别人。要连续地址空间是因为FORTRAN这些古老的语言假定连续内存空间,很多环境下甚至没有动态内存分配这么先进的东西。然而现在就算我们就算写C程序很多时候也都依赖malloc对连续空间的假定没那么强(well栈还是要的,越界后果还是严重的),而更多的时候我们在这层层抽象之上,再跑了一个VM, 然后用自带内存安全的语言,想想都觉得傻。
Singularity的一个起始点就是:如果从底层开始就是一个安全的managed语言构建系统,我们能删除很多这些抽象层和迷之策略,managed或者GC并不意味着又一层overhead, 反而,你会得到更简单,更安全可靠,也更快的软件系统。首先,你不需要很复杂的虚存管理,所有应用可以跑在一个地址空间上,由类型系统和运行时提供隔离。它也意味着上下文切换的成本非常低,你可以跟erlang一样做超级多并发轻进程。单一地址空间和GC可以让你很放心地零拷贝在进程间或与内核/驱动传递数据 —— 传统系统里很多的 CPU 都耗在 copy one buffer to another 和为之服务的 encode / decode 上,在这里你都不需要了。就像Joe Duffy在blog里说的,这样做出来的系统很多时候比传统的所谓native系统要快。
我觉得这样的文章和系统,就算最后没有推广实用,也还是极有启发性的。在那以后,我会去关注各种OS研究项目的脑洞。在各种项目中,我都会下意识地注意整个技术栈各层的设计假设,也常常发现这种因为过时的设计假设和没事加一层抽象的习惯导致的不合理设计,常常去 rethink the stack. 我会少很多自我限定,比如会直接忽略有runtime有GC就不能做系统编程之类的bs.
我们处在一个很奇怪的时代。不管是最新的手机还是最强大的后台集群,跑着的系统都是一个40多年前的UNIX的复刻+扩展版,还支持那个时代的API. 我们当然都不是在用 UNIX 的方式去用系统了,我们不会去fork进程然后用pipe通信,而是发明了各种各样不见得就更好的并发和通讯方式 —— 然而内核还是要支持像fork这种超级tricky的系统调用。经典的系统体系早已崩塌,我们要么在废墟上架无数层抽象,要么像epoll一样在内核上打洞,而未曾建立一个新的系统体系,这有点像罗马帝国崩溃后的中世纪。
Singularity / Midori 就是建立这样的新体系的尝试。Joe Duffy Midori 系列的每一篇文章都值得反复读,在每一个设计点上,在提出解决方案前,他总结了现有设计的思路和背景,分析根本问题所在,我认为每一篇都做到了 "rethinking the software stack". 我不完全同意某些具体的设计结论,但这样的思考是无价的。