最近华为高调发布了鸿蒙操作系统(HarmonyOS),基于微内核的全场景分布式系统,可以按需扩展,低延时,实现更广泛的系统安全。按照发布会的PPT来看,鸿蒙OS有三层架构,第一层是微内核,第二层是基础服务,第三层是程序框架。所谓的第二层基础服务应该就是那些从内核态空间移到用户态空间的基础服务程序。当然,也可能部分还是运行的内核态,更像是混合内核。
当下的鸿蒙OS依然是基于开源框架,只是关键模块自我研发,也就是说,和各大手机厂商使用Android开源系统实现各自的定制系统大概是一个意思。鸿蒙OS的愿景是2020年实现内核和应用框架自研,2021年实现软硬件协同优化。这里的软硬件协同优化,应该是要解决进程间通信(Inter-process communication, IPC)的性能问题,这个后面会详细说一下。
关于鸿蒙OS不过多评价,时间是检验真理的唯一标准。接下来主要聊一聊微内核的概念。
微内核(Microkernel or μ-kernel),这个概念其实是相对于宏内核(Monolithic kernel)而言的。
宏内核与微内核对比图
我们常说的Linux/UNIX就是基于宏内核的,内核提供了相当多的功能,包括驱动,调度器,地址空间管理,进程间通信,文件系统,虚拟文件系统,系统调用等,以Linux为例,其宏内核的代码量高达2700万行。
宏内核系统架构
而微内核仅提供调度器,地址空间管理以及进程间通信等最基础的功能,MINIX 3的微内核仅1.2万行代码。
微内核架构
宏内核与微内核代码量为什么会有这么大的区别呢?德国计算机科学家Jochen Liedtke提出的微内核最小化原则,简单的讲就是,宏内核所提供的所有功能,可以扔到用户态实现的,就一律扔到用户态,内核仅保留绝对必要的功能。这有点像奥卡姆剃刀原理,如非必须,勿增实体。也就是说,宏内核提供了大量的冗余功能,兼容了太多的硬件,代码量自然就大。而微内核甚至把硬件的驱动程序从内核剥离出去,使其运行在用户态。
早期的宏内核,其实很像我们今天所说的微内核。早期设备本身的内存空间有限,外设也极少,内核需要支持的特性也很有限。但是随着硬件的飞速发展,内核需要支持更多的特性和更多的外设,宏内核架构的复杂性和代码规模也就飞速增加起来了,内核程序间的耦合度也越来越大。当然,CPU速度的提升以及内存空间的增加,让我们基本上可以无视内核对性能的消耗。但是5G时代,一个万物互联(Internet of Things, IoT)的时代,将有更多的小型智能设备接入互联网,低功耗、低内存、安全性成为了新的要求,在这些设备上跑宏内核的系统绝对不是好的选择,由此,微内核的热度又起来了。
早在上个世纪八九十年代,微内核一度被炒的热火朝天。但是一直因为性能问题而没有得到广泛应用。直到今天,微内核在学界的热度也远超工业界。每一次发展微内核,都大致经历这样的过程:把内核的某些功能剥离出内核,然后爆发性能问题,然后再把一部分功能移回到内核。这样就出现了很多介于宏内核和微内核之间的内核形态,一般统称为混合内核。我们常见的Mac OS、Windows NT等用的就是这种混合内核的架构。
混合内核
近几年谷歌一直在研发Fuchsia系统,使用的Zircon内核,才算是真正意义上的微内核。
那么,微内核到底有什么优点呢?
分布式支持:微内核各模块采用IPC传递信息,对于IPC而言,无论是在本机,还是局域网或者广域网,只要赋予进程和设备唯一的标识符,微内核的设计几乎是天然支持分布式系统的。 模块化、低耦合:由于大部分服务程序被转移到用户态空间,系统就可以按需启动这些服务,按需接入外设。用户态的进程各自独立,系统耦合度大大降低。
组件故障不会导致系统重启,内核只需要重启故障组件就可以恢复正常,系统稳定性可以大大提高。熟悉Linux内核编程的人都知道,内核代码出问题,往往会导致整个系统崩溃。而用户态程序不仅不会导致系统崩溃,而且易于调试。
微内核系统功能升级也更容易,由于宏内核的很多功能都是运行在内核,跟随系统一起启动。虽然可以使用补丁实现故障修复和功能升级,但是依然有很多问题无法通过补丁解决,还是要依赖版本更换和重启整个系统。而微内核只需要替换相关组件,然后重启组件即可。 内核代码零缺陷:由于微内核代码量极少,可以从数学角度进行形式化验证,从而保证内核代码完全没有缺陷,也就是所谓的Bug free。但是这并不是说整个系统没有缺陷,系统本身还包括用户态的服务程序,说白了,只是把缺陷转移到相对安全的用户态罢了。
那为什么微内核直到今天也没广泛应用呢?
原因前面已经说了,微内核的低效率是硬伤。微内核依赖IPC实现通信,宏内核的IPC效率就很不尽人意,微内核则把IPC的低效率进一步放大了。相对而言,宏内核的文件系统,驱动等以线程的方式工作在内核空间,它们之间的通信可以都在内核完成,不需要上下文切换,可以直接访问共享资源,甚至可以直接相互调用接口达到通信的目的。而微内核则需要通过IPC通信,触发系统调用,内存拷贝(异步通信需要拷贝两次),运行上下文切换,阻塞进程,这些操作开销都很大。
Jochen Liedtke创造的L4 microkernel把IPC的系统开销降低了一个数量级。如何实现呢?
首先,直接弃用异步IPC,所有通信均使用同步的方式。 然后把通信数据尽可能直接使用寄存器传递(这个涉及CPU指令集,有机会再细说),这样可以减少数据拷贝、内存寻址、调度器切换运行上下文的开销。 最后为了解决同步通信造成进程阻塞的问题,引入了进程直接切换的概念,即当有数据发送时,当发送端发完数据时,直接将上下文切换到接收进程,迅速完成数据传递和接收。 除此之外,微内核效率差的另一个原因则是每指令的存储器周期比宏内核要长很多,这个就需要减少微内核的缓存工作集来解决问题了。 微内核效率差的原因除了IPC、指令存储周期长外,还有一个观念上的问题。华为鸿蒙OS的愿景是支持多终端,统一开发流程,也就是让一个微内核支持所有的应用场景。而提高微内核效率的一个解决方案却是,设计单一目的(Single-purpose)、专用的微内核。不知道华为鸿蒙OS是怎么解决这个问题的,还有点小期待呢。