type
status
date
slug
summary
tags
category
icon
password

微内核逐渐通用:鸿蒙微内核的性能与兼容性

1 简介

微内核将操作系统内核的功能最小化,并将诸如文件系统、设备驱动等组件(OS服务)进行隔离、优先级降级,以得到相对于诸如Linux的宏内核更好的可靠性、安全性、扩展性。
💡
实际上就是说把一部分非核心的功能移出内核,这样就能保证真正核心的部分不会因为这些边缘的功能而受到安全性的问题(比如在宏内核的模式下,由于文件系统与内核紧密结合,因此有一些病毒文件可能可以直接攻击到内核)。此外由于内核足够小,也便于维护,也就提高了可靠性。如果微内核再暴露出一组规范的接口,那么就可以实现相较于宏内核而言更好的扩展性(比如在微内核的情况下可以随意地替换文件系统,但是在宏内核中难度就比较大)
而正是由于这些特性,使得微内核已经被广泛应用于嵌入式、高安全性的场景之中。
在另一方面,当像Linux这样的宏内核占据了通用目的的场景(诸如服务、云等),也有新型的使用场景不断浮现(诸如智能设备、手机等),在这些使用场景下,要求更高的安全性、可靠性与可扩展性以便有更好的性能,但Linux并不适合在这些场景下使用。随着Linux逐渐通用,其在朝着服务、云的方向不断发展,以至于其在其他应用场景下性能并不理想。例如,Linux花费了超过十年的时间才打上了一部分的实时性(preemptive-RT)补丁,并且它的演变(应该是指这个实时性补丁)仍然不是主流,就更不用提其他特定领域的策略了。更重要的是,对LInux而言,其注定很难满足这些使用场景下要求的高水平的工业标准。
然而,尽管微内核已经被广泛研究了数十年,最先进的微内核主要还是面向特定领域,比如嵌入式以及高安全性的应用场景。微内核通常使用静态的资源分区和分配,并且没有通用的OS功能来运行商业的、现成的应用。
💡
比如内存空间等等,嵌入式系统上确实很少有堆分配器这种动态分配机制。
在下面,我们将总结一下我们在这些新兴场景下,将微内核改进为一个通用OS内核所面临的主要挑战。
兼容性:仅兼容POSIX的子集是不够的。
重建整个软件的生态环境是不实际的。因此,先进的微内核比如seL4、Zircon等,通过提供一个自定义的库(例如musl-libc,他生成(或提供?)进程间对OS服务的调用),兼容了POSIX的一个最小子集。然而,他们面临着部署的问题,例如二进制兼容性以及在新兴应用场景中实现的挑战(例如fork和poll)。
💡
二进制兼容性又称为ABI兼容,表示的是二进制库的兼容性(并且在通常情况下是动态库,因为静态库在使用的过程中会和源程序合成为一个程序共同编译,因此不会存在提供一个二进制静态库的情况)。比如我使用了一个动态库,并在这个动态库的基础上开发了一个程序。如果我在更新二进制动态库之后需要重新编译程序,那么就说明动态库不是二进制兼容的,反之则是二进制兼容的。
更重要的是,他们很难通过可以接受的工作量复用设备驱动,并且不降低性能。这对产品的部署是十分重要的。
性能:不止要考虑IPC(进程间调用、进程间通信)。性能在新兴的应用场景中是最重要的,它这季节决定了用户使用的体验。尽管最先进的微内核(如seL4)以及新的架构支持已经取得了很高的IPC性能,但是我们发现,他们仍然会造成不小的性能开销,因为当微内核变得通用的时候,IPC的频率会显著提高(智能手机上的IPC频率甚至是路由器上的70倍)。
💡
这里说到通用就会导致IPC频率提高,就我的理解而言,是因为在通用的场景下,完成一个业务需要涉及到的功能更多,也就使得参与的进程更多,自然IPC就变多了。比如原来只希望语音通话,可能只需要一个进程,但是现在为了通用性,可能需要支持潜在的视频通话需求,就需要更多进程来参与实现这个功能。
进一步来说,我们观察到了一个同样严重的性能问题。导致这个问题的原因是,为了多服务器设计而产生的状态双重记录机制。这引入了额外的性能开销(比Linux慢了2倍)以及内存占用(35%)。更重要的是,由于高频的调用,基于能力的访问控制(其会将经常更新的内核对象通过“能力”机制隐藏起来)会导致巨大的开销。例如,这个机制会导致页错误处理比Linux慢大概3.4倍。
我们在七年前开始了鸿蒙项目,以重新测试并改进HM微内核以便其能够成为一个能够在新兴场景中使用的通用OS内核。为了实现高效的部署,HM实现了对所有的Linux API/ABI的兼容性,并且对Linux应用程序与驱动生态都是兼容的,例如HM可以运行复杂的框架,如AOSP和OpenHarmony,他们具有丰富的外设。
💡
到这里就是说HM解决了兼容性的问题
尽管兼容性的目标会限制系统的性能,HM仍然把性能作为它的重点。因此HM遵行了微内核的设计理念,并没有做出过多的妥协。
💡
这里就说HM在性能上也有一定的保证
具体地说,HM有以下几个关键的设计:
  • 通过降级以及隔离的OS服务实现微内核的最小化
    • HM通过将必要的功能(如线程调度、串口时钟驱动以及访问控制)集成进内核,并将其他的组件作为独立的OS服务移出了内核,实现了最小化原则。另外,HM使用了低粒度的访问控制以保证“给最少的权限以实现更好的安全性”这一原则。因此,HM集成了微内核安全、可靠的特征。
  • 通过实现Linux API/ABI兼容与高性能的驱动复用最大化了兼容性。
    • HM通过一个二进制兼容(ABI兼容)的跳板标识并将Linux系统调用重定向到了IPC中,并借此进一步实现了完整的Linux API/ABI兼容,并在此基础上集成了现有的软件生态系统。更重要的是,HM通过一个驱动容器(驱动容器通过很少的工作量,提供了一个在HM上层的Linux运行时),复用了原生的Linux驱动,并且通过双驱动器实现了控制平面与数据平面的分离,减少了关键路径上的性能开销。
  • 由结构支持的性能。
    • HM在追求性能的同时没有违背微内核的体系结构原则。具体地说,HM采取灵活的组成,以便其可以在可信的服务之间,分层地放宽隔离性,实现了IPC开销的最小,并且使成组的服务紧耦合以最小化IPC的频率、消除在对性能要求很高的场景下的状态双重记录机制,同时又保留了将这些服务分离的能力以便能够满足对安全性要求更高的使用场景。
      💡
      IPC分离实际上就是操作的粒度变小,变小之后权限的控制就可以更精细,就可以满足对安全性要求更高的场景
我们已经将HM部署到了数以万计的设备上,包括智能路由、智能交通工具以及智能手机。在这些应用场景中,HM相较于Linux,不仅有更好的安全性和可靠性,还有更好的性能。通过正式地阐明设计,并且使用了自动化的验证以及验证指导测试证实了关键的安全属性(如整数与缓冲区移出),HM的关键组件进行了半正式的验证。HM已经有了ASIL-D与CC EAL 6+(这俩都是安全方面的认证)的认证。在路由器上,HM通过减少了30%的内存开销,允许额外的30%的用户接入。在交通设施上,HM的启动时间增快了60%,并且跨域延时减少了60%。在智能手机方面,HM使应用程序的启动时间缩短了17%,并且减少了10%的丢帧。

2 微内核概述

2.1 微内核简介

2.2 通用微内核的需求

2.3 Linux的问题

3 为了通用性重新审视微内核

3.1 大规模系统中的微内核

💡
这里应该还是指的HM微内核
在新兴的应用场景中使用微内核在性能和兼容性方面面临着巨大的挑战。表1展示了,在新兴场景中在产品中部署HM时所表现出的特点。对路由器而言,我们直接从产品使用环境中收集了数据。对交通设备和手机而言,我们重现了一个典型的使用场景(持续24小时),这个场景来自大量真实世界的执行记录(匿名并且已经征得用户同意)。
  • 发现1:在新兴应用场景中,IPC频率快速上升。
    • 表1a展示了在HM中,当在用户空间把所有的OS服务都设置为隔离时,IPC频率的CDF。
      💡
      CDF就是概率分布函数。稍微复习一下概率论,CDF求导就是概率密度函数,而下面提到的平均值实际上就是期望。
      智能手机(avg 41k/s)与交通工具(avg 7k/s)相较于路由器(0.6k/s,这个IPC频率已经跟传统专用的微内核没什么区别了)有更高的IPC频率。表1b,1e与1f通过展示次要数据(不是来自磁盘/设备的)描述了这一现象(也就是频率增高的问题)。
      💡
      图b描述的是手机中的页错误频率的CDF,图e描述的是各个系统调用的分布和频率,图f描述的是系统调用频率的概率分布函数。
  • 发现2:多服务分发导致双重备份
    • 由于没有集中管理一些资源,使得需要进行双重备份,进而导致额外的内存开销
  • 发现3:“能力”机制影响了协作
    • 就拿页表机制来说,由于“能力”隐藏了页表(页表是一个系统对象),就使得页表的更新对其他“能力”不足的系统对象是不可见的,这就使得其他系统对象处理页表的时候,在出现匿名页错误的时候,由于“能力”这一层机制的存在,就导致页错误的处理速度更慢。所以从更宏观的角度来看,“能力”机制影响了这些系统对象之间的协作。
  • 发现4:可移植性比遵守POSIX规则更重要
    • 主要就是在说一些现在比较先进的微内核的问题。这些微内核只是实现了POSIX的一个子集,就导致可移植性比较差。并且在微内核中文件系统已经被移出内核,就使得如何实现一个高效的文件操作也成为了一个挑战。
  • 发现5:部署需要高效的驱动复用
    • 全部重新实现驱动是不现实的(5000人年),因此需要去复用已有的驱动,但是原有的启动复用方案面临着可移植性、工作量、性能的挑战。

3.2 HM概述

HM设计原则
  • 保持最小化:HM为了保证拥有微内核的特性,所以还是会遵守最小化原则。在HM的内核中,只会保留线程调度器、串口时钟驱动、访问控制(访问控制的粒度很细)部分。其余的部分都被移出了内核。这就使得HM具有安全、可靠、可扩展这些微内核的特性
  • 优先考虑性能:微内核的各种优势是通过性能上一定的妥协实现的。但是HM并不强制执行微内核的标准导致过度的孤立,而是通过折衷满足了对性能和安全性二者的需求。
    • 💡
      在这里作者举了几个例子,说明HM采用分离的隔离类来减小IPC的开销。
      通过放松可信OS服务的限制来解决过度孤立的问题。
      合并一些紧密联系的IPC来实现IPC的降频。
      通过地址token来检查权限,实现高效的内核对象共同管理
      不难发现这些实际上就是在微内核基础上所作出的一些创新(按照传统的微内核机制是不允许这样的)
  • 最大化可移植性:HM通过一个shim,实现了所有的linux API,并且将linux系统调用进行了重定向。并且shim还负责将一些抽象的linux概念进行转义(如fd)以支持一些函数(poll)。
    • 此外HM还通过一个驱动容器复用了原生的Linux设备驱动。这个容器可以提供必要的运行时(直接根据Linux获取,并且代价比较小)
      HM还将控制平面和数据平面进行了分离
HM的威胁模型
HM的威胁模型跟大部分先进的微内核是相似的。都能阻止恶意应用程序的执行,也可以防止一些系统服务访问其他的地址空间,进而保证了系统中数据的保密性、完整型、可用性。但是相较于一般的微内核威胁模型还是有一定的区别:
  • HM没有统一的内存管理器
  • 为了性能,HM还做了一些改变,后面会详细介绍

4 HM的性能设计

4.1 同步类RPC的IPC FastPath

需要注册一个处理函数作为入口,此外还需要准备一个栈池。当应用程序执行一个服务的时候,内核会在一个调用栈中记录服务请求者的栈/指令指针,并切换到处理函数执行(处理函数会在一个准备好的执行栈中执行)。在返回的时候,HM会从调用栈中将调用者的栈和PC指针pop出来,并切换到服务的调用者。如果需要进行参数传递,就使用共享内存的方式进行。
在这种情况,在处理IPC的时候就不会出现进程的切换(也就是bypass了调度)。但是即使采用这种切换机制,还是会存在一些性能的降低,比如需要切换特权级、地址空间、缓存污染。
 
 
 
 
 
 
notion image
 

杂记

  • IPC:进程间通信
  • RPC:远程进程间通信
  • state double bookkeeping:状态双重记录
  • Capability-based access control(基于能力的访问控制)
    • 能力(Capability)是一个不可伪造的令牌,包含了对特定资源的访问权限
  • cross-domain latency
  • Anonymous Page Fault 与 Mapped File Page Fault
    • 首先需要先知道无论是哪种Page Fault,都是在虚拟内存机制中,在内存中找不到某一个页导致的缺页错误
    • Anonymous Page Fault:Anonymous Page Fault 通常与匿名内存映射(Anonymous Memory Mapping)有关。匿名内存映射是指没有与文件或设备关联的内存区域,通常用于堆、栈和动态分配的内存(如通过 malloc 分配的内存)。
      • 💡
        所以当这些动态分配的变量不在内存中时,就会出现这一种缺页错误。
    • Mapped File Page Fault:Mapped File Page Fault 与文件映射内存(File-Mapped Memory)有关。文件映射内存是指将文件的内容映射到虚拟内存地址空间中,使得文件的内容可以像内存一样被访问。
      • 💡
        所以当访问的文件的某一个页没有在内存中缓存时,就会出现这一种缺页错误
 
计算机系统结构ML
Loading...
Noah
Noah
永远年轻,永远热泪盈眶
公告
❗❗复习笔记问题❗❗
由于兼容性问题
导入md文件可能导致了一些格式错误
🌹如发现格式错误,请联系我~🌹
🌹如博客内容有误也欢迎指出~🌹