抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Linux_Bcc_Ext4_Latency_Tracing

Linux Bcc Ext4 Latency Tracing

浅谈原子操作

所谓原子操作,就是要么不做,要么全做。在很多场景中,都有对原子操作的需求。在翻aep的spec文档时,也发现了一个巧妙的方法。所以顺便发散性地总结一下各种实现原子操作的方法,水平有限,欢迎拍砖。

小粒度——指令

根据intel手册卷三第八章的描述,x86使用三种机制来实现原子操作:

  1. Guaranteed atomic operations。Guaranteed atomic operations是指一些基本的读写内存操作,这些操作都是保证原子性的。一般来说,读写位于一个cache line中的数据是原子性的。
  2. bus lock,使用LOCK#信号和指令的lock前缀。锁总线的方式很简单,进行原子操作的cpu会在bus上assert一个LOCK#信号,此时其他cpu的操作都会被block住。
  3. cache lock,利用cache一致性协议(MESI协议)来实现。如果要访问的内存区域已经在当前cpu的cache中了,就会利用cache一致性协议来实现原子操作,否则会锁总线。

intel早期cpu(如Intel386,Intel486,奔腾处理器)实现原子操作,是通过bus lock来实现的。这种实现的问题,是完全不相关的两个cpu之间,也会相互竞争总线锁,从而导致整体性能下降。在后来的cpu中,intel对这一问题进行了优化。当要进行原子操作的内存已经被拉入cache中时,cpu会使用cache一致性协议来保证原子性,这被称为cache lock。相比于bus lock,cache lock粒度更细,能获得更好的性能。
x86中,有些指令是自带lock语义的,比如XCHG,更新段描述符等等;另外一些指令可以手动加上lock前缀来实现lock语义,比如BTS, BTR,CMPXCHG指令。在这些指令中,最核心的当属CAS(Compare And Swap)指令了,它是实现各种锁语义的核心指令。不同于自带原子语义的XCHG,CAS操作要通过”lock CMPXCHG”这样的形式来实现。一般而言,原子操作的数据长度不会超过8个字节,也不允许同时对两个内存地址进行CAS操作(如果可以的话,免锁双向链表不是梦)。
原子操作中另一个绕不开的话题是ABA问题,水平有限,就不展开讲了。简单提一个例子,在linux内核的slub实现中,用上了一个宏cmpxchg_double,这并不是同时对两个内存地址进行CAS的黑魔法,而正是利用CMPXCHG16B指令解决ABA问题的宏函数,有兴趣的可以深究一把。

大粒度

当原子操作的对象大小在16字节或者8字节以内时,一两条指令就能实现原子操作。但是,当对象的大小较大时,实现原子操作的就需要其他方法了,比如加锁和COW。深究这两种方法,可以发现在本质上,它们还是将问题转换成了16字节的原子操作。

加锁

加锁这个方式很好理解,只要一加锁,整个临界区的操作就可以被看作一个原子操作。
内核中提供了各种各样的锁,自旋锁,读写锁,seq锁,mutex,semaphore等等,这些锁对读写者的倾向各有不同,在是否允许睡眠上也有所不同。
简单来说,自旋锁和读写锁的核心都是利用原子指令来CAS操纵一个32位/64位的值,它们都不允许睡眠,但是读写锁对于读者做了优化,允许多个读者同时读取数据,而自旋锁则对于读写操作没有什么偏向性。seq基于自旋锁实现,不允许睡眠,但是对写者更为友好。mutex和semaphore也是基于自旋锁实现的,但是它们允许互斥区的操作陷入睡眠。
可以看到,加锁这种方式,最核心的还是利用指令实现原子操作。

COW

针对大对象原子操作的另一种方式是COW(copy on write)。
cow的思想其实非常简单,首先我们有一个指向这个大对象的指针,在需要原子性修改这个大对象的数据时,因为没办法做到inplace修改,所以就把这个对象的数据拷贝一份,在对象副本上修改,最后再原子性地修改指向这个对象的指针。可以看到,这里最核心的地方是利用指令来实现指针的替换。
关于COW,这里举一个AEP的例子。AEP是一种存储介质,这里只需要知道它可以按字节寻址数据在掉电后不消失即可。普通的磁盘,一般有扇区原子性的保证,也就是在将新数据写入某个扇区的途中突然掉电的话,这个扇区上要么完全没有新数据,要么新数据完全被写下去了,不会出现一半新一半旧的状态。扇区原子性的保证很重要,许多数据库都依赖它,然而,AEP这种存储介质没有这种保证,所以需要用软件的方式来做这种保证,称为BTT。
BTT的思路也很简单,为了方便理解,后文我不引入AEP的术语来进行描述。
首先把整个存储空间划分成若干个block,每个block有自己的物理块号,然后再维护一个表来做逻辑块号到物理块号的转换。给上层逻辑块的数量略小于物理块数量,这样就会有一部分的物理块没有被映射,姑且称为free block。
比如下图,4个逻辑块,5个物理块,其中1号块是free block。

接下来,在往一个逻辑块上写数据时,先找一个free block,把数据写上去,接下来去映射表中,将逻辑块的映射修改该free block。整个流程中,最关键的一步——修改映射关系——是原子性的。只要有这个保证,那么就能够提供block数据原子性更新的能力。
COW的思想在很多地方都有,比如qemu的qcow镜像快照,ext4和btrfs在写入数据时的cow,linux内核的rcu机制等等。此外,cow最有名的使用场景莫过于fork的实现了,但是它只是单纯的为了减少拷贝开销,与原子性没有太大关系。

COW优化

cow的方式,有个很麻烦的事情,就是每次都得原子性得去更新指针。那么有没有办法去掉这个指针呢?有的。
这个是在intel关于AEP的文档上学到的另一种取巧的方式(注意,下面描述的例子和上文中的BTT没有任何关系)。起因是这样的:
AEP的驱动使用一个称为index block的结构来管理元数据,这个index block处于整个介质的起始位置,大小至少为256字节。有些操作会去更改它的多个字段的值,所以可能出现更改字段到一半的过程中掉电的情况,因此需要一种机制来保证更改过程是原子性的。
正常的COW方式,需要在起始位置处保留两个index block大小的空间以及一个指针,其中一个index block作为备用。在修改index block的数据时,以cow的方式将全部的数据存储在备用index block中,然后以COW的方式更改指针指向该备用index block中。
intel使用下面的机制来优化掉指针:
依然是两个index block,index block中有一个称为seq的字段。seq是一个两位的数,共有4个状态。除去00状态,还有01、10、11三个状态,将这三个状态视为一个循环,如下:

为了方便叙述,两个index block分别命名为blockA和blockB。

  • 第一次写入数据,写入到blockA中,其上的seq为01;
  • 第二次写入数据,写入到blockB中,其上的seq为10;
  • 第三次写入数据,写入到blockA中,其上的seq为11;
  • 第四次写入数据,写入到blockB中,其上的seq为01;

如此往复,在恢复时,只要读取并比较两个index block上的seq中哪个处于循环的前方,就能找到最新的那个index block。这样的优势是显而易见的,一是避免了额外的指针,或者说把指针固化到两个index block中,避免了一个8字节指针对两个index block对齐带来的麻烦;二是少一次写操作,提升了效率。

多对象

前面针对的都是一个个单个的对象,如果涉及到多个对象,要保证原子性就比较复杂了。比如,如果使用加解锁的方式,就需要注意锁的顺序,防止死锁的问题;如果是cow的方式,就需要注意中途失败以后的把已替换的指针回滚回去的问题。从更大的格局来看,针对多个对象的原子操作,本质上就是进行一次事务操作。所以,这个问题的解法,参考事务的实现就好了。

写日志

事务的四大特征ACID,即原子性,一致性,隔离性和持久性,基本上是一个常识了,而原子性只是事务的一个特性。
写日志算是实现事务最通用的方式了,日志一般分为redo和undo两种日志,为了加快恢复速度,一般还会引入检查点(checkpoint)的概念。在文件系统和数据库的实现中,基本上都能看到事务的身影。
写日志除了能保证原子性和一致性以外,还对磁盘这种外存设备很友好,因为写日志基本上都是顺序的。在这一方面的典型案例,当属日志结构文件系统和leveldb的LSM-tree了。
leveldb的原理想必不用再提了,它把对于K-V对的增删改操作都变成一条条的日志,然后持久化为磁盘上的一个个SST,之后再触发合并整理。这样一来,基本上对于磁盘的所有操作都是顺序的了。
日志结构文件系统也是类似的思想,它将文件数据的增删改操作直接变成日志写到磁盘里面,文件的实际数据不需要单独再存到某个地方,而是靠日志恢复出来。这种做法对写操作是非常友好的,但是读方面的性能就有点差强人意了。

事务内存

事务通常是用于保证持久性数据一致性的。去掉持久性的要求,将事务的概念引入到对于内存对象的操控中,就有了事务内存的概念。
正如上文所说,对于多个对象的操作,加锁和cow的方式,在使用时都比较麻烦。加锁的方式要考虑加解锁顺序防止死锁,中途失败了还要按照特定的顺序解锁回滚;cow也是一样,虽然没有死锁的问题,但是在回滚上也是很麻烦的。另一个问题就是,针对不同的场景,加解锁的顺序要重新考虑,cow的回滚也要重新考虑,不具有通用性。
事务内存机制则是为了解决这些问题而提出的,它把针对多个对象的原子操作抽象为一个事务,只要按照它提供的api,以串行化的思路去编程就行了。不用考虑加解锁的顺序,也不必考虑回滚的问题,在遇到了某些fatal error时只要abort掉事务即可。这是一种通用的并发编程方式,简化编码的同时,还能保证并发的性能。
事实上,事务内存机制的内部实现,也是依赖于cow机制和加解锁来实现的,更深一步,其实也是依赖于原子操作指令的。

总结

总结一下:
16字节或8字节以内的内存数据,使用cpu的原子操作指令;
16字节以上的数据,使用加锁、COW的方式,或者优化过的使用seq的COW方式,本质上还是依赖于原子指令;
针对多个对象的原子操作,引入事务或者事务内存的概念,实际上的实现要么是写日志,要么是依赖于cow或加锁的方式,最终依赖于原子指令。
所以,万变不离其宗,原子操作指令很关键。

参考链接

  • https://pmem.io/documents/NVDIMM_Namespace_Spec.pdf
  • https://software.intel.com/content/dam/develop/public/us/en/documents/325462-sdm-vol-1-2abcd-3abcd.pdf
  • https://zhuanlan.zhihu.com/p/151425608
  • https://zh.wikipedia.org/wiki/%E8%BD%AF%E4%BB%B6%E4%BA%8B%E5%8A%A1%E5%86%85%E5%AD%98

OpenAnolis开源社区的萌芽与发展

编者注:10月24日,2020中国开源年会暨阿帕奇中国路演在长沙举行,阿里云智能高级技术运营专家金运通应邀在操作系统分论坛上做了主题为「OpenAnolis开源社区的萌芽与发展」的演讲。本文内容根据其演讲内容整理而成。

img

以下是演讲全文:

近些年开源在国内变得非常流行,开源理念也得到了越来越多的开发者及公司的认同,机缘巧合,我的职业生涯几乎都在和开源打交道,这里先和大家分享一下我与开源的缘分。

img

这张图相信很多人都见到过,它介绍了云计算的技术发展,从最左边的2000年开始,当然我参加工作没有那么早,但我第一次参与开源项目的贡献确实是在SUN 这家公司,那时候国内开源贡献者还是一个很小众的群体,当时我在openSolaris开源社区做桌面系统,包括Firefox开源浏览器的工作,记得在08年随着Firefox 3.0的发布,它一周内的下载量就超过了2000w,这让我第一次切身见证到了开源的力量。

后来SUN这家公司被收购了,已经消失在IT发展历史的长河中,而它的衰落恰恰是和开源相关,虽然后期整个公司实行全面开源的战略,当时也是业界最大的开源公司之一,但因为它开源的战略实施的太晚了,没能赶上产业发展的历史潮流。

所以我觉得开源不仅仅是一种新的开发、协作方式,对公司而言也是一个新的商业战略以及通过开源与产业界构建一种新的产业关系。

这张图里把SUN放到最开始的位置,标称为单台机的发展阶段,但其实它一度对IT界有着非常大的影响,也有很强的技术洞察力。Sun不仅发明了Java语言,它在很早的时候就提出“网络就是计算机”的概念,这些都为后来云计算的发展奠定了基础。

后来VMware在2001年开始虚拟化的工作,AWS在06年开启了云计算元年,我也在11年 加入IBM KVM开源虚拟化团队, 当时也没有意识到开源虚拟化会成为的云计算发展的强劲推动力,并成为整个云计算技术栈的基石,那时KVM也才刚刚出来,身边还很少有人谈论云计算。

后来OpenStack横空出世,掀起了开源云计算的浪潮,我在Intel有幸见证了OpenStack的蓬勃发展,比如本次大会上的开源黑客松的活动,我在15年参加第一届的OpenStack黑客松,当时只有Intel、华为等3家公司,十几个人,现在的黑客松活动有近30家公司,近百人参与,它也见证了开源越来越多的得到了国内开发者及公司的认同。

后来随着容器技术的发展和云原生的兴起,我也参与了kata Containers项目,也因此结识国内很多容器的开发者。所以回顾我的职业生涯,好像云计算发展的每个技术浪潮我都赶上,但我认为这不是能说明我对技术发展有多好的判断力,而是因为开源,你会发现,开源往往会让你处于技术发展的前沿。

所以,反过来想,如果我是在开源电子货币领域,现在是不是也财务自由了哈。。。

但现实是我又回到操作系统这一传统的领域,之前一直在系统厂商,做开源系统软件,服务于硬件系统平台,现在来到阿里云做系统软件的开源,那一个云计算公司做系统软件开源与硬件系统厂商做又有什么不同的地方呢?

为了回答这个问题,我们先来聊一下社区发起的初衷,再对社区做个介绍,最后和大家一起来探讨社区未来的发展。

社区萌芽

当来到阿里云操作系统团队之后,我发现操作系统这一领域在云计算时代面临着新的挑战,也一直是在老树发新芽:比如云计算的大规模部署所带来的稳定性要求,以及随着云计算规模的扩大,每一点的优化和性能的提升都会带来可观的经济收益,所以云平台的全栈集成和优化也就成为云平台的核心竞争力之一。另外,云计算是希望能够像水、电一样为业务应用提供了即插即用的计算资源,把业务从基础设施中解放出来 ,使得用户可以更加关注业务的创新,而操作系统作为离业务应用最近的一层,需要提供和其他云产品一样的长期稳定版的支持和SLA保障,这也是云平台能力的重要部分。

随着过去10多年阿里云的发展,操作系统团队也一直在探索和实践,构建了Alibaba Cloud Linux来满足云计算场景的需求,比如对于稳定性的增强,对启动速度和性能的提升,对多架构的支持并支持线上业务应用,对资源隔离、安全的加固,以及LSA的支持等。

img

但慢慢我们发现这些问题是云计算时代大家都普遍面对的挑战,而其中的很多问题不是仅靠一个部门,一家公司就能够有一个很好的解决方案。比如对异构平台生产可用的支持以及硬件能力的快速引入,并构建软硬一体的集成和优化,就需要和各硬件生态来紧密合作。再比如为了满足云计算及互联网业务场景带来的需求,越来越多的云服务商以及系统厂商在定制自己的发行版,由此带来整个发行版生态越来越碎片化,与上游社区的关系也在不断的分化和远离,这些又需要去从整个云计算的生态来解决。

而这就有了OpenAnolis操作系统开源社区的破土而出。

img

Anolis,is Not just Linux System,社区的名字是一个递归缩写,灵感来自GNU,也正如其名字所寓意,OpenAnolis社区并不仅仅是一个单一的操作系统发行版社区,为了满足云计算场景的发展需求,整个社区包含3个部分:

  1. 社区开源项目:聚焦技术创新,弥补技术栈上的缺失,并为未来技术布局。目前社区包括云场景的cloud kernel,云原生Java JDK项目Dragonwell ,机密计算LibOS项目Occlum,机密容器项目Inclavare Containers ,系统诊断工具Diagnose,后续计划会有开源更多项目加入。
  2. 社区兴趣小组SIG:很多时候也被称为项目组,在很多操作系统社区被用来作为打包项目的组合,比如Desktop SIG,来构建所有桌面软件包,或者是存储SIG包括了整个存储系统栈的包。但OpenAnolis社区中的SIG更多的是从如何满足云计算对系统栈的需求出发,来提供全栈集成的垂直应用方案,来打造云平台技术的领先性。比如kernel只是一个单一的软件包,而在社区里面延伸出不同子系统和领域的多个兴趣小组,并与上层应用垂直打通。再比如针对云原生、AI、大数据等场景,也会各自有不同需求点的多个SIG。
  3. 开源发行版:所有社区的开源项目,和SIG的开发工作,最终都依托一个面向云场景的开源发行版分发出去。

社区也在和众多的生态伙伴建立合作关系,对于IHV来说,系统软件和硬件平台是天然的双螺旋的生态,社区希望和IHV一起把新硬件平台能力带给应用,充分挖掘平台性能,推动硬件平台的快速演进和迭代。

对于OSv来说,构建一个适用于云计算的OS是大家共同面对的问题,会有很多相互学习、合作的机会,社区希望和OSV一起提供更优质的,适用于云计算的操作系统服务。

对于ISV来说,操作系统作为离业务应用最近的一层,社区希望和ISV一起让应用更好的长在云上,提升端到端的性能,推动业务的敏捷性。

下面和大家介绍一下社区项目及SIG

img

Cloud Kernel,针对云计算场景的需求,基于上游kernel的LTS版本构建的开源Kernel版本,针对云上基础设施,结合各类云的应用进行了很多特性的开发和优化,比如对稳定性提升,系统资源隔离的增强,云上配置及应用集成的优化,来满足云计算场景的需求。

https://github.com/openanolis/cloud-kernel

Inclavare Containers, 它是一个面向机密计算场景的、开源、容器运行时,致力于把机密计算带进云原生时代。

它也是并被OCI(Open Container Initiative)容器规范组织正式接纳为OCI容器标准实现,也就是说Inclavare Containers机密计算容器运行时和runC及Kata Containers一样成为了OCI容器标准的实现之一。它是由阿里云操作系统团队、容器服务团队,并联合蚂蚁可信原生团队发起,并和Intel等进行开源共建;

https://inclavare-containers.io/

Dragonwell是一款开源的、生产就绪型Open JDK 发行版,被内部阿里电商业务和外部云上客户所广泛使用,它着力于在重塑云上的Java语言。比如它提供了Java 静态编译技术,通过单独的编译阶段将 Java 程序编译为本地代码,在运行时无需传统 Java 虚拟机和运行时环境,只需操作系统类库支持即可。将一个应用的启动速度从 60 秒优化到 3.8 秒,适应了云上的应用尤其是在函数计算场景的需求。

同时它还有对协程的支持,线程阻塞式调度会变成更轻量的协程切换。之前大家使用Go语言的时候就,特别喜欢它的一点就是协程机制。现在Dragonwell也把协程带到了Java语言。

http://dragonwell-jdk.io/

Occlum 是一个用于机密计算的LibOS开源项目,通过抽象硬件上的机密计算能力,大幅降低了机密计算应用开发的门槛,是机密计算生态重要的一环,也是Inclavare Containers默认的机密计算应用程序框架;

http://occlum.io/

Diagnose tools 也是阿里云操作系统团队开源的一款系统诊断利器,通过深入探测系统运行时的数据来快速定位linux操作系统各种性能异常、抖动问题。

https://github.com/alibaba/diagnose-tools

社区SIG介绍

目前在社区围绕内核有4个初始SIG,包括:

核心服务SIG:核心服务是内核与应用之间的关键系统层,通过对核心的用户态组件进行深度优化,来提供云上高可靠、高性能的核心服务。比如通过对systemd这一系统及服务管理器的改造,解决了cgroup 膨胀引发的集群抖动、挂载泄露(mount leak)等问题,提高了系统的稳定性。

高性能存储SIG:在云场景下,网络存储的技术栈会更长,同时新的存储硬件也在快速更新迭代,这都推动了存储栈的创新发展。比如Intel有兴趣在社区构建围绕Persistent Memory的高性能存储软件栈,对PMEM的协议提供完善的支持,同时和上层应用匹配,比如支持Persistent Memory的Redis方案,构建端到端的高性能存储应用方案。

跟踪诊断技术SIG:跟踪诊断技术是操作系统中必不可少的基础能力。随着云计算的大规模部署以及软件栈的复杂性不断提高,给系统的诊断和运维带来了挑战,传统的人肉运维肯定是不行了,所以云平台需要构建一套自动的、智能运维中台,来自动的收集线上系统数据,提供智能的健康诊断和问题发现,并构建智能的客服来响应问题,同时还需要提供自动的、不停机的、热修复和主动的故障隔离,来实现问题的自动修复。

社区开源系统诊断利器Diagnose tools,可以深入的探测系统运行时的数据,并致力利用更多的开源共建来构建自动的、智能的系统追踪诊断平台;

资源隔离SIG:资源隔离是容器的支撑技术,社区在内核层对主机的内存、CPU、网络、IO资源隔离有着全面的增强,比如率先完善了对cgroup v2的支持,解决了长期以来对IO资源无法彻底限制的难题,利用Intel RDT技术来对CPU LLC(Last Level Cache)的隔离,避免noisy neighbors的对性能的干扰,保障了云上虚拟资源的SLA;

同时,资源隔离的增强还应用在资源混部场景,经过电商业务的长期实践,可以显著的提高CPU等资源的利用率。社区还在探索资源混部与K8S资源调度的结合,欢迎对该领域有兴趣的开发者来一起探索。

为了让大家更好的了解社区SIG的工作,这里拿高性能存储SIG中的一个项目为例:

img

io_uring 是内核5.1中的新异步 IO 框架,io_uring 为了避免IO在提交和完成事件中的内存拷贝,设计了一对共享的 ring buffer 用于应用和内核之间的通信。社区在用FIO来测试,发现在pull的模式下,其性能堪比SPDK;

社区开发者围绕io_uring机制,一方面贡献上游内核社区,并在Cloud Kernel中对其提供完善的支持,另一方面为了能把这一新机制用起来,在与上层应用的匹配上,做了很多探索,比如利用io_uring对Redis中IO流程进行了改造,使得Redis的性能最多提高30%。再比如对Nginx web引擎的适配,使得Nginx长连接的情况性能提升超过20%。但上层的应用是纷繁多样的,在不同的应用场景中如何最大化的发挥这一IO特性,希望大家能够在社区中做更多的讨论。

云原生SIG

随着云原生的发展加速了应用和基础架构的解耦,充分释放云的弹性;对企业而言,云原生可以帮助企业优化云架构,发挥云的最大化价值。而系统层的复杂性则下沉到基础设施,使得云原生系统层服务边界不断上移,这给系统层带来新的挑战的同时,也给了系统层更大的优化和创新空间。

img

这是云原生开源软件栈的一个架构图,其中,沙箱容器用在Serverless等云原生的场景中提供更安全的隔离能力,在函数计算场景中,Java等语言运行时也下沉到了系统层。比如阿里云沙箱容器2.0通过和云场景的Redis数据库、Java语言的垂直优化,整体性能比在普通容器上还要高;

社区的云原生SIG致力于发展云原生系统全栈开源技术,从开放的硬件多架构的支持,到云场景的操作系统,从与业界共建cloud hypervisor到推动kata containers2.0架构的设计与实现,以及下一步3.0的演进,从对K8S整合到Java语言的云原生化,以此推动整个云原生系统层技术的演进,实现从硬件到应用的全栈优化。

云原生机密计算SIG

云原生机密计算SIG致力于把把机密计算的能力带给云原生应用。机密计算用于保护云上的敏感代码和数据,不会被其他恶意的第三方来窃取和破坏,“哪怕对于最不情愿采用云的组织而言,现在也有机密计算等一些技术可以解决它对安全的顾虑,而不用担心是不是可以信任云提供商。”所以机密计算被认为是未来5-10云计算的必备技术。

img

但是一个云原生的机密计算环境涉及到全栈系统,从硬件的TEE解决方案到到操作系统及虚拟化,从k8s的资源管理及编排到容器运行时,从到LibOS在再到语言runtime,OpenAnolis 云原生机密计算兴趣小组希望通过孵化Inclavare Containers和dragonwell等项目,并连接其他开源社区,和业界一起通过开源、协作来推动这个目标的实现。

新模式,新生态

前面我们对OpenAnolis社区有了一个整体的了解,不论是社区的愿景目标,还是社区组织和架构都有着显著的特点,都着力于解决云计算对系统软件发展的需求,那么这样一个面向云计算的操作系统社区,它的发展会给Linux发行版带来什么样的新模式,以及围绕社区会构建出什么样的开源新生态呢?

发行版新模式

img

业务闭环: 相比于传统的发行版,面向云计算场景的发行版有着业务闭环,传统的发行版社区或者厂商仅负责OS本身,但OS从发布到为业务提供服务的中间还有很长的路径,包括硬件提供方OEM做验证,再由不同的信息集成商,做基础设施的搭建,再到集成应用方案,最后才能交付给客户。而在云计算场景,整个过程都是由云计算提供方来完成,因为客户对于云平台需求的是业务应用的托管平台,这就形成了从OS到业务的闭环。这种闭环对于OS本身的影响,一方面是OS可以和整个云计算平台栈更好的集成和优化,另一方面,作为云平台提供方可以更贴近应用场景,更方便快捷的获得业务对OS的需求和反馈;

端到端的应用方案: 在云原生的时代,业务应用是生在云上,长在云上,系统层和基础应用层甚至语言运行时都下沉到基础设施,所以对业务的需求而言,不论是对于硬件架构,像X86、ARM的CPU还是GPU,XPU等,还是云平台的资源能力像网络、计算、存储、安全等,以及像AI、大数据等应用领域,都需要云平台来提供一个端到端的应用方案,同时这也是社区SIG想要去解决的问题。

快速迭代和演进:由业务的闭环和端到端的应用方案的需求推动了云计算平台对于OS的快速迭代和演进,使得OS能够更快的对新计算架构的支持,对硬件能力的最大化的利用,对新技术的采用,来满足业务对新方案需求,并以此更好的推动软硬件的发展。

开源新生态

img

围绕OpenAnolis社区将会构建出一个开源的新生态。

全栈开源生态:随着云计算软件栈越来越复杂,对应用服务边界的上移,以及对全栈的集成和优化的需求,社区通过SIG从某个云计算需求点、技术点出发来构建全栈的开源技术能力,从硬件的新平台、新特性到系统层的最优架构,再到应用层的适配,从而推动软硬件协同的发展及应用生态繁荣;

全方位开源:社区通过开源项目、兴趣小组SIG以及开源发行版构建了一个立体的、全方位的开源生态。

开源赋能业界:社区也在发展完备的IHV,OSV,ISV等合作伙伴生态,社区和生态伙伴的合作也将会是一种新的合作关系和发展出新的合作领域,并携手活跃的开发者及用户来一起合作、共赢,成为云计算发展的最强动力。

云计算在为企业数字化转型提供源源不断的动力,相关技术也在持续的快速演进,操作系统处于整个云基础设施的中间层,它向下管理和抽象了硬件资源,向上支撑了云平台及云上的业务应用,在整个云计算架构中扮演关键角色,如何构建一个满足云计算发展需求的操作系统是我们在云时代共同面对的问题,欢迎大家能参与到OpenAnolis社区,一起来构建云平台系统技术底座,推动云计算的向前发展。谢谢!

img

让容器应用管理更快更安全,Dragonfly_发布_Nydus_容器镜像加速服务

镜像对容器部署的挑战

img

在容器的生产实践中,偏小的容器镜像能够很快地部署启动。当应用的镜像达到几个 GB 以上的时候,在节点上下载镜像通常会消耗大量的时间。Dragonfly 通过引入 P2P 网络有效提升了容器镜像大规模分发的效率。然而,用户还是必须等待镜像数据完整下载到本地,然后才能创建自己的容器。我们希望进一步缩减镜像下载的时间,让用户能够更快地部署容器应用。同时,如何更好地保护用户数据,也是容器行业近年来的重要关注点。

为此,我们为 Dragonfly 项目引入了一个容器镜像加速服务 Nydus。Nydus 能够极大缩短镜像下载时间,并提供端到端的镜像数据一致性校验,从而让用户能够更安全快捷地管理容器应用。Nydus 由阿里云和蚂蚁集团的工程师合作开发,并大规模部署在内部的生产环境中。作为云原生生态的一部分, Nydus 在生产环境的优秀表现,让我们有信心现在将项目开源,让更多的容器用户能够体验到容器快速启动和安全加载方面的能力。

容器镜像加速服务 Nydus 地址:

https://github.com/dragonflyoss/image-service

Nydus: Dragonfly 的容器镜像服务

img

Nydus 项目优化了现有的 OCI 镜像标准格式,并以此设计了一个用户态的文件系统。通过这些优化,Nydus 能够提供这些特性:

  • 容器镜像按需下载,用户不再需要下载完整镜像就能启动容器
  • 块级别的镜像数据去重,最大限度为用户节省存储资源
  • 镜像只有最终可用的数据,不需要保存和下载过期数据
  • 端到端的数据一致性校验,为用户提供更好的数据保护
  • 兼容 OCI 分发标准和 artifacts 标准,开箱即可用
  • 支持不同的镜像存储后端,镜像数据不只可以存放在镜像仓库,还可以放到 NAS 或者类似 S3 的对象存储上
  • 与 Dragonfly 的良好集成

架构上, Nydus 主要包含一个新的镜像格式,和一个负责解析容器镜像的 FUSE 用户态文件系统进程。

img

Nydus 能够解析 FUSE 或者 virtiofs 协议来支持传统的 runc 容器或者 Kata 容器。容器仓库、OSS 对象存储、NAS 以及 Dragonfly 的超级节点和 peer 节点都可以作为 Nydus 的镜像数据源。同时,Nydus 还可以配置一个本地缓存,从而避免每次启动都从远端数据源拉取数据。

镜像格式方面, Nydus 把一个容器镜像分成元数据和数据两层。其中元数据层是一棵自校验的哈希树,每个文件和目录都是哈希树中的一个附带哈希值的节点。一个文件节点的哈希值由文件的数据确定,一个目录节点的哈希值则由该目录下所有文件和目录的哈希值确定。每个文件的数据被按照固定大小切片并保存到数据层中,数据切片可以在不同文件以及不同镜像中的不同文件共享。

img

Nydus 能为用户带来什么?

img

用户如果部署了 Nydus 镜像服务,最直观的一个感受就是,容器启动变快了,从以前的明显时间消耗,变成了几乎瞬间就能启动起来。在我们的测试中, Nydus 能够把常见镜像的启动时间,从数分钟缩短到数秒钟。

img

另外一个不那么明显但也很重要的改进,是 Nydus 能够为用户提供容器运行时数据一致性校验。在传统的镜像中,镜像数据会先被解压到本地文件系统,再由容器应用去访问使用。解压前,镜像数据是完整校验的。但是解压之后,镜像数据不再能够被校验。这带来的一个问题就是,如果解压后的镜像数据被无意或恶意地修改,用户是无法感知的。而 Nydus 镜像不会被解压到本地,同时可以对每一次数据访问进行校验,如果数据被篡改,则可以从远端数据源重新拉取。

img

未来规划

img

前面我们介绍了 Nydus 的架构和优点。在过去的一年里,我们和内部的产品团队一起致力于让 Nydus 项目更稳定、安全和易用。在把 Nydus 项目开源之后,我们将会更关注广泛的云原生容器生态。我们的愿景是,当用户在集群中部署 Dragonfly 和 Nydus 服务的时候,无论镜像大小,用户都能够方便快捷地运行他们的容器应用,同时不需要为容器镜像的数据安全性担忧。

OCI 社区容器镜像标准

img

我们已经在内部生产环境中大规模部署 Nydus,而我们坚信对 OCI 镜像标准的改进需要广泛的社区合作。为此,我们积极地参与了 OCI 社区关于下一代镜像标准的讨论,并发现 Nydus 能够广泛地符合 OCI 社区对下一代镜像格式的要求。所以我们提议把 Nydus 作为 OCI 社区下一代镜像格式的示例实现,并期待和更多的云原生行业领导者们一起推进下一代镜像标准的制定和实现。

FAQ

img

Q1:现有的 OCI 镜像标准有什么问题?

A1:SUSE 的 Aleksa Sarai 写过一个 blog (The Road to OCIv2 Images: What’s Wrong with Tar?),详细描述了现有 OCI 镜像标准的一系列问题,简单总结就是 OCI 镜像标准使用的 tar 格式太古老,并不适合作为容器镜像格式。

Q2:Nydus 和 CRFS 有什么区别?

A2:CRFS 是 GO build team 设计的一个镜像格式。二者在主要设计思想上非常相似。细节上, Nydus 支持块级别的数据去重和端到端的数据一致性校验,可以说是在 CRFS 的 stargz 格式上的进一步改进。

Q3:Nydus 和 Azure 的 Teleport 有什么区别?

A3:Azure Teleport 更像是现有 OCI 镜像标准在基于 SMB 文件共享协议的 snapshotter 上的一个部署实现,能够支持容器镜像数据按需下载,但保留了所有目前 OCI 镜像 tar 格式的缺陷。相对的,Nydus 抛弃了过时的 tar 格式,并使用 merkle tree 格式来提供更多的高级特性。

Q4:如果运行基于 Nydus 的容器的时候网络断了怎么办?

A4:使用现有 OCI 镜像的时候,如果在容器镜像还没有完整下载的时候网络断了,容器会一开始就无法启动。Nydus 很大程度上改变了容器启动的流程,用户不需要再等待镜像数据完整下载就能启动容器。而容器运行时如果网络断了,将无法访问没有下载到本地的镜像数据。Nydus 支持在容器启动后在后台下载容器镜像数据,所以当容器镜像数据完整下载到本地后,基于 Nydus 的容器也不会受到网络中断的影响。

附录:OClv2 镜像标准

img

从 2020 年 6 月开始,OCI 社区花了一个多月时间密集讨论了当前 OCI 镜像标准的缺陷,以及 OCIv2 镜像格式需要满足哪些要求。OCIv2 在这里只是一个宣传命名,实际上 OCIv2 是当前 OCI 镜像标准的改进,而不会是一个全新的镜像标准。

这次镜像格式大讨论从一个邮件和一份共享文档开始,并促成了多次在线的 OCI 社区讨论会议。最后的结论也很鼓舞人心,OCIv2 镜像格式需要满足下列要求:

  • 更少的重复数据
  • 可重建的镜像格式
  • 明确的更少的文件系统元数据
  • 可以 mount 的文件系统格式
  • 镜像内容列表
  • 镜像数据按需加载
  • 可扩展性
  • 可校验和/或可修复
  • 更少的上传数据
  • 可以工作在不可信存储上

在共享文档中可以找到每一个要求的详细描述。我们全程参与了整个 OCIv2 镜像格式要求的讨论,并发现 Nydus 很好地满足了全部的这些要求。这进一步促使我们开源 Nydus 项目来为社区讨论提供一个工作的代码基础。

共享文档链接:https://hackmd.io/@cyphar/ociv2-brainstorm

img

云原生底层系统思考

前言

img

编者注:10月25日,首届中国云计算基础架构开发者大会(简称CID)在长沙召开,阿里云智能共分享5个演讲主题,阿里云智能资深技术专家韩伟东也在会上做了主题为云原生底层系统思考」的技术演讲。本文内容根据其演讲内容整理而成。

img

(图/阿里云智能资深技术专家韩伟东)

以下是演讲全文

云原生的发展

img

经过云计算十几年的发展和普及,用户逐渐从迁移上云演进到更好地使用好云的阶段。在传统模式下设计和实现的应用没法最大化的利用云计算基础设施的特点和能力,所以开发者开始基于云计算设施去设计和实现应用,这就是所谓的从云里长出来的云原生应用。2015年Matt Stine给出了twelve-factor applications来定义云原生应用。2018年,CNCF给出了更全面的云原生定义,不仅涉及到应用,也包括代表技术、基础设施、运维等,可以说云原生已经从最初的应用层扩展到整体云计算技术栈。

img

相比于IaaS,云原生应用场景有很多的不同,比如应用特点上有有状态和无状态以及长生命周期和短生命周期的区别,用户使用体验上有购买资源和按需使用服务的区别。所有这些差异点,能够很好的体现出云原生在提升效率和降低成本上的优势。

img

我们站在用户视角和系统视角来看一下云原生的变化。用户视角看,一个很大的变化是可以业务不相关的工作从应用剥离下沉到底层平台,用户只需要关心业务逻辑。

img

系统视角看,系统提供的用户服务界面上移,从物理资源层、虚拟化资源层上升到应用开发和运行层,云原生应用之下的底层系统技术栈变深。

img

云原生底层系统定义

img

服务界面上移这个变化使得应用开发和运行层之下的技术栈都变成了云厂商的内部系统,这需要从整体上重新去审视如何打造这个系统。我们从这个角度出发,给云原生底层系统做了一个定义:单机上支持应用代码和应用容器运行的整个软件系统。云原生场景下,在单机上是云原生应用+云原生底层系统,另外在集群层面,还有云原生应用平台,这个平台负责编排调度、服务治理、智能运维等。

img

云原生底层系统的构建思路

img

首先我们考虑云原生底层系统需要具备什么样的核心能力。

第一个能力是隔离性,在公有云场景,多租户的安全隔离是最基本的要求,同时在私有云场景和serverless架构下各种业务应用混部部署,以及云原生轻量化后产生的高密部署,需要底层系统提供性能隔离和故障隔离上的保障。

第二个能力是兼容性,云计算是社会性的基础设施,面对的是全场景的用户,通用也是最基本的要求,云原生作为云计算新阶段,也必须保证好通用性,从底层系统上来说,需要有技术创新,但是需要做好各种兼容,应用兼容、服务兼容、云原生技术生态和标准兼容等,降低用户升级到云原生的门槛和成本。

第三个是效率,这是支撑实现云原生核心价值的能力,包括,资源效率:减少资源损耗,提高资源使用效率,降低成本;弹性效率:快速启动、并发效率等;运行效率:高性能。

img

IaaS时代的运行单元是虚拟机,云原生时代需要什么样的运行单元?在企业内部,容器是一种很好的运行单元,但是普通容器存在很明显的缺陷就是隔离性,公有云场景的多租户安全隔离,私有云场景下性能隔离和故障隔离也不理想。兼顾隔离性、兼容性和效率,我们认为安全容器将会是云原生时代的重要运行单元。

实现安全容器有几种技术流派:

img

第一种是基于轻量级虚拟化和容器技术相结合的MicroVM,这种方案整体上在隔离性、兼容性和效率更优,也是目前业界最主流的方案,各大云厂商都在积极投入。

下图是MicroVM的基本架构。

img

第二种是基于进程级虚拟化的应用内核方案,由于采用全新的用户态内核,兼容性不够好,同时对性能也有一定的影响。第三种是libos/unikernel,让应用带上轻量化的内核,一般都需要修改应用,兼容性不好。

安全容器作为运行单元已经体现出隔离性、兼容性和轻量化资源开销的好处,接下来我们看一下弹性效率方面。

启动速度是实现弹性效率的关键。

我们以一个应用容器的启动为例,可以分成如下几个主要的阶段,首先镜像加载是一个很耗时的阶段,一般需要网络下载和解压,需要用到按需加载或缓存等方法加速。网卡和磁盘的创建也比较耗时,要做到极速需要用到预创建这样的方法。安全容器自身的启动,需要通过轻量化设备模型和精简内核等方法。应用启动速度跟语言和应用自身有关,一般来说java应用启动会比较慢,这方面已经有人在探索java启动加速的相关技术。

img

这里稍微展开介绍一下我们在镜像加速上的方案。为了解决镜像下载和解压耗时大,以及镜像解压后无法再被校验,无法感知恶意篡改的问题,阿里云智能和蚂蚁集团的工程师一起实现了Nydus镜像加速服务,实现新的镜像格式,分成元数据和数据两层,并实现一个用户态文件系统,可以按需加载下载启动容器镜像,大大缩短镜像加载时间,并提供端到端的镜像数据一致性校验,从而让用户能够更安全快捷地管理容器应用。Nydus已经正式开源,在CNCF Dragonfly项目中引入Nydus镜像加速服务。

欢迎大家关注和参与Nydus项目,开源代码地址:

https://github.com/dragonflyoss/image-service 。

img

接下来简单介绍一下实现底层系统高性能的思路。因为底层系统技术栈很深,而且这些技术栈是不直接暴露给用户,所以为打破边界和重塑提供了机会,我们的核心思路是通过全栈优化来实现高性能,从最底层的软硬协同,到host和guest 内核的上下协同甚至融合,到最上面的中间件和预研runtime跟OS的垂直优化。

img

到这里我们把计算相关的部分告一段落,接下来看看底层系统的其它方面。

在Kubernetes服务网络方面, kube-proxy基于netfilter框架,性能和扩展性比较差。Service mesh引入sidecar架构,数据链路上额外增加网络上一跳,影响性能。我们的一个思路是通过eBPF来加速这些网络,对于Kubernetes网络,基于eBPF实现一种新的服务网络和服务策略 tc-ebpf。tc-ebpf位于Linux协议栈的L2层,可以hook网络设备的入、出双向流量到eBPF实现的datapath。性能相比kube-proxy有明显的提升。对于service mesh,我们采用基于eBPF的sockmap进行加速。sockmap允许将TCP连接之间的数据转发过程卸载到内核中,从而绕过复杂的Linux网络协议栈直接在内核完成socket之间的数据转发操作,减少了上下文切换以及用户态和内核态之间的数据拷贝操作,优化TCP连接之间socket数据转发的性能。

img

关于云原生底层系统的存储,我们从问题和场景需求两方面入手。

首先对于9pfs作为安全容器rootfs的问题,我们建议采用virtio-fs替换9pfs,可以从性能上有数倍的提升。Serverless场景高密部署和按需短时生命周期执行请求的特点,高速临时存储将会很重要,一方面可以考虑对现有的存储处理进行一定的简化提升性能,另一方面也可以考虑通过高速介质(比如AEP、内存)进行加速。

img

安全方面,除了前面提到的多租户安全隔离,以及兼容支持各种云计算的安全服务之外,还要考虑云原生技术和安全技术结合支持新的业务场景。机密计算是一种解决数据安全的新方法,是在一个基于硬件的可信执行环境(TEE)中保护数据执行计算。为了在云原生场景支持机密计算,我们实现了Inclavare containers,一种在硬件强制实施的TEE中运行enclave runtime和可信应用的新型容器运行时:

  • 兼容容器生态:OCI runtime和容器镜像标准

  • 基于Library OS技术,改善enclave引入的约束条件所带来的兼容性问题

  • 提供对高级语言Runtime的支持,进一步提升泛用性

  • 定义通用的Enclave Runtime PAL API规范,构建Enclave Runtime生态

img

Inclavare containers项目已经开源,开源项目官网:https://inclavare-containers.io 。

开源代码:https://github.com/alibaba/inclavare-containers。

欢迎大家关注和参与!

阿里巴巴云原生底层系统:袋鼠

img

介绍完我们对云原生底层系统的一些思考,也简单看一下我们构建的云原生底层系统:袋鼠

我们不仅仅实现安全容器和inclavare containers这样的全新运行单元,而且在云原生底层系统整体层面构建了一些关键能力。袋鼠已经开始规模化地支撑阿里巴巴的云原生产品和业务。

img

小结

img

云原生在重构整个软件生命周期,是一项体系化的工作,整体上云原生还处于早期阶段,云原生技术正在快速的发展演进。我们的判断是云原生底层系统将会迎来一波的技术创新高峰,我们在这里分享的一些思考主要是抛砖引玉,面向未来,希望能够跟同行们一起推动云原生底层系统技术的创新和突破,构建更好更强大的云原生服务提供给广大的用户。

招贤纳士:

寻找有内核、虚拟化、容器、网络、存储、安全等系统技术经验,并有志于打造云原生底层系统的优秀人才,欢迎联系我们(邮箱:shaokang.hwd@alibaba-inc.com)。

阿里马涛:重新定义云时代的开源操作系统__人物志

img

随着云计算的发展,以及Linux平台的不断发展和生态系统的不断完善,越来越多的企业、云服务提供商都将Linux作为其数据中心的首选操作系统。

不过,作为云基础设施的底座,针对云上产品和环境进行定制、优化的需求大幅增长。基于此,阿里巴巴操作系统团队开发了 Alibaba Cloud Linux,以连接阿里云各类产品与客户应用,更好发挥云端的能力。

在近日的“长沙1024程序员节”期间,CSDN 「人物志」栏目采访了阿里云研究员、基础软件部操作系统团队负责人马涛,他介绍了在5G、云计算等技术的冲击下,云操作系统面临的挑战和机遇。

马涛也是阿里巴巴集团内核团队创始人之一。他曾先后在ORACLE,阿里巴巴负责Linux以及操作系统内核相关的研发工作,已在Linux内核主线有超过300个提交,同时对分布式文件系统,分布式存储等领域有多年深入研究。

以下为采访内容,由CSDN整理:

CSDN:随着5G、云计算等新技术的发展,新硬件架构层出不穷,这对底层的操作系统提出了哪些挑战?阿里的开源云操作系统在技术上要如何做出调整以适应这种变化?

马涛:确实,云计算及互联网场景对于操作系统的需求和传统时代有了很大的变化,稳定性、性能等方面都有了新的挑战。

首先云计算是规模经济,所以云基础设施的固定成本十分庞大。而当这些基础设施建成后,进行进一步扩张所需要的边际成本则相对较小,所以随着云服务提供者规模的扩大,其平均成本将会呈现迅速下降的趋势。

在如此大规模部署的情况下,稳定性就显得至关重要,再加上云上业务的复杂性和系统的高负载,这都对操作系统的稳定性提出了更高的要求。在阿里云我们有上百万规模的部署,所有对稳定性的挑战是非常巨大的。

另外,随着云计算规模的扩大,每一点的优化和性能的提升都会带来可观的经济收益。但云架构中单单某一层优化很难有可观的性能收益,这需要从硬件平台到系统软件,再到应用层全栈协同。

而这里操作系统恰恰处于中间的最为关键的点,它向下抽象物理IT资源,并利用抽象的资源向上支持应用。所以如何优化云计算操作系统提供全栈的集成和优化能力,这就成为了云操作系统的新机会,也是云平台的核心竞争力。

CSDN:像华为等巨头也入局并提出了新的操作系统,那么,阿里在开源操作系统上做出的调整与其他巨头有什么不同?

马涛:这里就要提到我认为云时代操作系统的第二个挑战,就是异构平台及特性的快速引入需求。

随着智能化对云计算能力需求的增长和IT产业的变革,推动了多CPU架构的快速演进,我认为将来任何一朵云都不会运行在单一的计算架构之上。所以这需要操作系统能够发展开放的硬件生态,完善的支持跨平台架构,同时,每一个硬件平台的迭代和能力的演进在不断加速,但传统的一些操作系统发行版的版本升级速度偏慢,没有办法把新硬件平台的能力及时带给云上丰富的应用。

大家经常会发现,一个硬件的特性可能已经存在1-2年甚至更长的时间,一些集成了这些特性的操作系统从才会姗姗来迟,这让应用无法及时的利用这些硬件的红利,让云平台的资源被浪费,让新硬件迭代的速度也大大降低。所以我们希望能够通过云平台的操作系统让客户更快的体验到各种各样的新硬件带来的技术红利。

从这一点上来说,我们做操作系统和Intel这些硬件厂商做操作系统的诉求是不一样的,他们更看重的是自己的硬件生态,比如CPU。而我们则需要考虑云客户的需求如何得到更好的快速满足。

CSDN:你们在开源操作系统上的下一个着力点是什么?

马涛:除了前面提到的稳定性、性能、异构性之外,云原生也是我们发力的一个重点。云原生加速了应用和基础设施的解耦,充分释放了云的弹性。云原生让开发者更加关注自身的业务应用,基础设施自身的复杂性则完全下沉到用户不可见的领域。同时对于云原生基础设施而言,它对应用的服务边界在上移,其系统软件栈在不断下移,这对云原生系统层提出的不少新的要求和挑战。

第一,资源粒度会更加细致。相较于传统的虚拟机时代的业务类型,云原生应用对于资源的需求类型有了变化,从传统机器虚拟化的资源即虚拟机形态,到虚拟OS的资源(即容器形态),再到虚拟运行时的资源(比如类似于函数计算形态的FaaS),应用对于资源的抽象层级要求更高以及粒度要求更细。

第二,弹性速度需要更快。云原生业务天然伴随着对快速弹性的需求以及短时运行等特征,要求云基础设施能够在短时间内,快速地提供资源,并且能够承受资源频繁的创建、销毁所带来的压力。

第三,性能要求更高。在云原生场景中,用户更专注于应用逻辑,更多的系统技术栈则下沉到基础设施,同时系统服务边界在上移。这样就给底层系统更多的施展空间,因为原有一些分层边界可以被打破,可以融合和垂直优化。

第四,安全隔离更强。随着云原生加速朝着Serverless计算架构演进,应用与基础设施彻底解耦合,用户只需关心自己的应用,而云原生系统不断下移。容器作为云原生的支撑技术,区别于之前的虚拟机计算架构,Serverless计算架构中云上的多租户安全成了一个全新的挑战。

针对这些云原生系统的新要求和新挑战,我们的操作系统也要做相应的变化,并做大幅度的革新才能满足快速增长的云原生应用需求。

CSDN:生态也是构建开源操作系统的非常重要的部分,阿里是怎么搭建相应的生态和社区的?

马涛:操作系统处于一个至关重要的中间层,它向上对接业务,向下对接硬件,所以我们希望围绕Alibaba Cloud Linux开源操作系统来构建一个支持多架构的、开放的操作系统生态。

我们希望和IHV合作伙伴一起,把新硬件平台能力带给应用,充分挖掘平台性能,推动硬件平台的快速演进和迭代;希望和OSV一起提供更优质的,适用于云计算的操作系统服务;希望和ISV让一起让应用更好的长在云上,提升端到端的性能,推动业务的敏捷性;希望和开发者和用户一起,打造更适合云计算的开源操作系统,构建云原生系统底座,推动云原生的发展。

CSDN:从阿里做开源操作系统的经验出发,阿里在做这些开源基础软件时踩过的坑有哪些?

马涛:开源基础软件面临的最大问题主要是两个,一个是生态建设。从2010年开始,阿里集团淘宝部门的内核团队就开始做操作系统内核的开源工作,之前我们的工作虽然在国内外取得了很大的成绩, 但是由于其他厂商无法深度参与,所以发展的一直不温不火。痛定思痛,我们觉得一定要做好生态,才能保证基础软件社区的健康发展。

CSDN:你也曾在Oracle工作过,相比国内外做开源操作系统,目前国内操作系统的发展又哪些优点和不足?

马涛:我在Oracle工作过4年多,从事操作系统相关的研发工作。相比而言,国内在操作系统领域的人才储备相对薄弱,无论是从业人员的数量还是职业技能方面都还处于劣势。当然我也非常欣喜的看到最近这些年包括阿里、腾讯等在内的很多国内企业都开始加大了在操作系统领域的投入,我们正在迎头赶上。

CSDN:有哪些建议提供给国内做开源基础软件的公司?

马涛:基础软件相对而言是入门是比较困难的,如何吸引更多的开发者参与开发是非常重要的。如果没有大量的开发者,我们就无法聚集群体智慧,没有办法做到长期稳定的发展。这里Linux Kernel通过一些非常简单的入门级别的修复来吸引新开发者的加入,非常值得国内开源基础软件的学习。

CSDN:从开发者的角度,操作系统作为三大基础软件之一,想要入局必须具备深厚的基本功,你对操作系统之路上的开发者们的技术成长上,是否可以分享一些经验?

马涛:这个话题很有意思。我以前是从Oracle开始做操作系统的,当时主要是给Linux内核贡献一些OCFS2(Oracle Cluster File System V2)的代码。我的第一个内核patch发生在2007年,当时我发现了内核代码的一段函数有一个变量是没用的,所以就写了个移除这个变量的patch发送到内核社区,并很快就被接受了。这件事情让我意识到Linux操作系统社区对于新人是非常友好的,而我也有能力去为操作系统做一些事情,也促成了我后面在操作系统十几年的持续耕耘。

有意思的是,由于是第一次写patch,所以我还把自己的名字写错了,在committer一栏写成了Tao Mao。所以如果你想进入操作系统研发,第一步并不是那么难,只要你有意愿,也一定能从一些一些小事做起并最终成就自己。

有了一个好的开始之后,第二个非常重要的是兴趣。我始终觉得兴趣是驱动我们不断学习,不断进步的基础。我非常清楚的记得,自从进入Linux操作系统的内核研发之后,基本上每个春节我都是在写代码中渡过的,因为那段时间自由度比较高,另一方面可以和国外工作的同事更好的交流。

回想起来,从代码中体会到参与感和幸福感是我能持续坚持做操作系统研发非常大的驱动力。

CSDN:你怎么看近年来“国产”基础软件的开源热度?国内开发者面临的挑战和机遇有哪些?

马涛:随着云计算的发展,IT基础设施在面临一场新的变革。在这场变革的浪潮中,无论是公共云还是混合云,以阿里为代表的新兴云计算厂商,在全球云计算的激烈竞争中表现亮眼。云计算带来了业务场景的新变化,带来了底层硬件的新需求,云原生意味着编程模型的革命,这些都对于我们基础软件是新机遇、新挑战,目前我们和国际顶尖厂商正在同台竞技,力争定义出适应下一代云计算发展的基础软件。

CSDN:如果要推动中国开源操作系统或者开源生态发展的话,你最希望与国内开发者一起推动什么样的共识和行动?与CSDN这样的开发者社区合作的话,你希望双方为开发者做些什么?

马涛:操作系统是基础软件的核心之一,也是核心竞争力之一。过去由于国内在底层硬件技术方面长期和国际顶尖水平有一定的差距,导致我们的操作系统研发一直有些落后。但是随着云计算最近几年的蓬勃发展,我们正处在一个快速变革的时代,云上操作系统应该长成什么样其实是一个非常崭新的话题,对我们是一个巨大的机会。

我期待能够和国内开发者一起定义出云时代的操作系统标准,也希望能够和CSDN一起培养出云时代的操作系统研发人员,并通过云时代的操作系统影响云时代上层应用软件生态的发展。

img

阿里云官方推出操作系统“等保合规”镜像_--_Alibaba_Cloud_Linux_等保2.0三级版

前言

img

Alibaba Cloud Linux 2(原Aliyun Linux 2)是阿里云操作系统团队为云应用场景打造的一款云操作系统。随其发展,使用该系统的用户对安全的需求也不断增加。另一方面,根据国家信息安全部发布的《GB/T22239-2019信息安全技术网络安全等级保护基本要求》,其中对操作系统提出了一些等级保护要求。那么如何快速构建符合网络安全等级保护制度2.0(简称等保2.0)规定的云服务器,有效降低手动配置的人力成本,尽量减少误操作带来的安全隐患,成为诸多企业,尤其是银行、保险、证券等金融客户迫切需要解决的难题之一。针对这一需求,阿里云官方推出操作系统“等保合规”镜像 —— Alibaba Cloud Linux 等保2.0三级版,并免费开放给阿里云上的用户使用。具体使用方式请参考:Alibaba Cloud Linux等保2.0三级版镜像使用说明:

https://help.aliyun.com/document_detail/186245.html

背景

img

网络安全等级保护制度是我国网络安全领域的基本国策、基本制度。1994 年,国务院发布《计算机信息系统安全保护条例》147 号令。该条例首次提出“计算机信息系统实行安全等级保护”,安全等级保护理念由此诞生。

2007 年和 2008 年,国家颁布《信息安全等级保护管理办法》和《信息安全等级保护基本要求》。这被视为“等保1.0”。为适应新技术的发展,解决云计算、物联网、移动互联和工控领域信息系统的等级保护工作的需要,2019年,由公安部牵头组织开展了信息技术新领域等级保护重点标准申报国家标准的工作,等级保护正式进入“等保2.0”时代。

产品介绍

img

Alibaba Cloud Linux 2 在阿里云正式发布以来,在阿里云上积累了大量客户。为了切实解决广大客户在“过保”中遇到的困难,实现“等保操作系统”的开箱即用,在阿里云云安全团队的支持下,阿里云官方操作系统“等保合规”镜像 —— Alibaba Cloud Linux 等保2.0三级版镜像应运而生。本产品基于公共镜像Alibaba Cloud Linux 2 LTS版本打造,在保障原生镜像兼容性和性能的基础上进行了等保合规适配,帮助用户摆脱复杂的加固操作和繁琐的配置,让用户享受开箱即用的操作系统等保环境。

Alibaba Cloud Linux 等保2.0三级版镜像按照《信息安全技术网络安全等级保护基本要求(GB/T 22239-2019)》进行加固。具体而言,它满足以下检查项:

https://yuque.antfin-inc.com/docs/share/b1a99688-ecff-4512-b864-445ab7878a53?inner=GoCKk

https://yuque.antfin-inc.com/docs/share/b1a99688-ecff-4512-b864-445ab7878a53?inner=GoCKk

检查项类型 检查项名称 危险等级
身份鉴别 应对登录的用户进行身份标识和鉴别,身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换
身份鉴别 当对服务器进行远程管理时,应采取必要措施,防止鉴别信息在网络传输过程中被窃听
身份鉴别 应具有登录失败处理功能,应配置并启用结束会话、限制非法登录次数和当登录连接超时自动退出等相关措施
访问控制 应对登录的用户分配账户和权限
访问控制 应重命名或删除默认账户,修改默认账户的默认口令
访问控制 访问控制的粒度应达到主体为用户级或进程级,客体为文件、数据库表级
访问控制 应及时删除或停用多余的、过期的账户,避免共享账户的存在
访问控制 应授予管理用户所需的最小权限,实现管理用户的权限分离
访问控制 应由授权主体配置访问控制策略,访问控制策略规定主体对客体的访问规则
安全审计 应对审计记录进行保护,定期备份,避免受到未预期的删除、修改或覆盖等
安全审计 审计记录应包括事件的日期和时间、用户、事件类型、事件是否成功及其他与审计相关的信息
安全审计 应启用安全审计功能,审计覆盖到每个用户,对重要的用户行为和重要安全事件进行审计
安全审计 应保护审计进程,避免受到未预期的中断
入侵防范 应能发现可能存在的已知漏洞,并在经过充分测试评估后,及时修补漏洞
入侵防范 应遵循最小安装的原则,仅安装需要的组件和应用程序
入侵防范 应关闭不需要的系统服务、默认共享和高危端口
入侵防范 应能够检测到对重要节点进行入侵的行为,并在发生严重入侵事件时提供报警
入侵防范 应通过设定终端接入方式或网络地址范围对通过网络进行管理的管理终端进行限制
恶意代码防范 应安装防恶意代码软件,并及时更新防恶意代码软件版本和恶意代码库

阿里云操作系统团队通过专业的技术,依托阿里云云安全的专业检测程序,结合自身测评经验对云服务器相关配置进行深度分析和持续优化,最终精心打磨构造出这款等保合规操作系统镜像,显著降低客户手动配置的人力成本,有效规避人为误操作带来的安全隐患,帮助用户实现:

  • 无需逐一单机配置操作系统等保合规项,即可批量创建等保合规机器;
  • 无需深入理解操作系统等保合规技术,即可快速实现操作系统合规;
  • 无惧配置修改引起的系统故障,即可实现默认安全合规配置;
  • 无需安全预算投入,即可免费获取官方等保合规镜像。

产品实现

img

首先,我们结合阿里云云安全中心的能力识别当前Alibaba Cloud Linux 2 LTS已经满足和还未满足的等保项,通过分析所有风险项的描述,总结发现:

1、每个风险项包含至少一个小项,只有修复该风险项下所有的小项才能修复该风险项。

2、有的风险项比较灵活,需要用户交互,比如“应对登录的用户分配账户和权限 访问控制”这一项,需要除系统管理用户之外,应该至少再分配三个用户:普通用户、审计员、安全员帐户。这些账户的名字与密码需要用户自己设定,因此归为用户交互项。

3、有些风险项不需要用户交互,但是会限制用户的登陆以及访问权限,比如:“应通过设定终端接入方式或网络地址范围对通过网络进行管理的管理终端进行限制 入侵防范”,会限制登陆机器的IP;“应授予管理用户所需的最小权限,实现管理用户的权限分离 访问控制”,会限制su命令的访问权限;“应重命名或删除默认账户,修改默认账户的默认口令 访问控制”,会禁止root用户登陆。这几项虽然不需要与用户交互,但是如果执行后很有可能用户无法访问机器,从而影响机器的正常使用,所以应该尽可能地在等保加固时考虑不影响机器的正常使用,是加固时需要考虑的难点。

4、剩余的一些风险项既不需要用户交互,也不影响机器的正常使用,比如:“应关闭不需要的系统服务、默认共享和高危端口 入侵防范”。这类风险项一般加固建议比较明确,可以直接按照对应的检查项能够很快写出脚本来修复。

因此,在等保加固时,我们把加固脚本分为两大类,一类是“非交互脚本”,直接在镜像构建时加载。另一类是“交互脚本”,需要用户在首次登录系统后,手动运行它来进一步加固配置,使用方式参见Alibaba Cloud Linux等保2.0三级版镜像使用说明:

https://help.aliyun.com/document_detail/186245.html

意义

img

伴随云时代的飞速发展,企业上云的步伐也在逐渐加快,越来越多的客户将阿里云作为企业上云的不二选择,并将 Alibaba Cloud Linux 这一阿里云官方操作系统作为业务部署的底层系统,其中很重的原因就是相信阿里云官方能够将操作系统的维护做到最好,等保镜像这一产品意味着阿里云在云产品开发和交付的过程中将安全作为重要组成部分,将合规融入到产品的“血液”中,把安全植入产品的“骨髓”里,能够帮助有等保诉求的客户快速便捷的上云。

联系我们

img

产品页:https://www.aliyun.com/product/alinux

文档:

https://help.aliyun.com/document_detail/111881.html

钉钉群:Alibaba Cloud Linux OS 开发者&用户群

img

终于,SM2国密算法被Linux内核社区接受了!

背景

img

国密,是国家商用密码的简称,由国家密码管理局制定算法标准,同时也制定了大量的产品及接口规范以及应用场景。

随着近年来外部的国际贸易冲突和技术封锁,内部互联网的快速发展,IOT领域的崛起,以及金融领域的变革愈演愈烈。摆脱对国外技术和产品的过度依赖,建设行业网络安全环境,增强我国行业信息系统的安全可信显得尤为必要和迫切。

密码算法是保障信息安全的核心技术,尤其是最关键的银行业核心领域长期以来都是沿用3DES、SHA-1、RSA等国际通用的密码算法体系及相关标准。

2010年底,国家密码管理局公布了我国自主研制的“椭圆曲线公钥密码算法”(SM2算法)。为保障重要经济系统密码应用安全,国家密码管理局于2011年发布了《关于做好公钥密码算法升级工作的通知》,明确要求“自2011年3月1日起,在建和拟建公钥密码基础设施电子认证系统和密钥管理系统应使用国密算法。自2011年7月1日起,投入运行并使用公钥密码的信息系统,应使用SM2算法。”

自2012年以来,国家密码管理局以《中华人民共和国密码行业标准》的方式,陆续公布了SM2/SM3/SM4等密码算法标准及其应用规范。其中“SM”代表“商密”,即用于商用的、不涉及国家秘密的密码技术。

这其中值得我们关注的主要是以下公开的算法:

  • SM2:基于椭圆曲线密码(ECC)的公钥密码算法标准,提供数字签名,密钥交换,公钥加密,用于替换RSA/ECDSA/ECDH等国际算法

  • SM3:消息摘要算法,哈希结果为256 bits,用于替换MD5/SHA1/SHA256等国际算法

  • SM4:对称加密算法,密钥长度和分组长度均为128 bits,主要用于无线局域网标准,用于替换DES/AES等算法

  • 国密证书:这里的国密证书指的是使用国密算法(SM2-with-SM3)的标准X509格式证书,证书使用SM3作为哈希算法,使用SM2作为数字签名算法

  • 国密SSL:采用国密算法,符合国密标准的安全传输协议,也就是SSL/TLS协议的国密版本

SM2进阶Linux内核之路

img

目前Linux内核已经较好的支持了SM3和SM4算法,这得益于无线局域网标准的广泛使用。但SM2算法和国密证书迟迟没有得到支持,也就无法基于国密来建立全栈可信和内核中的完整性验证,因此在内核中支持这一套体系也变得迫切起来。整个规划是:在内核中支持SM2算法和国密证书,在内部业务率先应用起来后,最终推进到社区。

整个流程下来,诸多不顺,权且记录下来。

第一回,有了规划,接下来就是考虑如何实施。但凡密码学算法,都会先考虑是否可以从openssl做移植。幸运的是,openssl对SM2/3/4支持得非常好,椭圆曲线算法的实现久经考验,非常成熟,而且最新版本也完整支持了国密证书。不幸的是,openssl的各个模块之间藕合度很高,要实现SM2和国密证书,需要移植openssl架构和基础设施代码,包括BIGNUM、ECC、X509等。这个工作量无疑是巨大的,即便实现了,这种方式也很难被社区接受,再三考虑权衡后,果断放弃了这条”捷径”。

第二回,发现了一个令人惊喜的事实:内核中已经有了一个椭圆算法的基础实现(crypto/ecc.c),何不尝试基于这个算法来做呢?于是参照SM2规范开始coding,但结果有点遗憾,这个椭圆算法在SM2上居然失效了,连最基本的点乘结果都是错的!纳尼?剧本不应该是这样的。于是发邮件咨询该算法的一个资深开发者,很快就得到了下面的回复(感叹天下还是好心人多):

Shamir's trick algo is probably generic, but it's ecc_point_double_jacobian()that is curve specific.
Algorithms are chosen that are fit curves I (and previous coders) used.You need to check their properties carefully if you going to use them.
Some variants of used algos, that may fit other curves, are in referencedpapers (in comments).

总结原因:这个算法是经过高度优化的算法,是精确适配过NIST和ECRDSA椭圆曲线参数的,并不一定适合国内的SM2曲线参数,看来这条路是走不通了……

……哭泣中,别理我。 ……擦干眼泪,看成败,人生豪迈,不过是从头再来……

第三回,经过反复探索,发现内核中RSA算法是基于一个mpi(高精度整数)库实现的,这个库来源于libgcrypt(这是知名隐私保护软件GnuPG的底层算法实现)。内核中已经实现了一个早期版本的mpi,当时就是为了实现RSA引入的。现在的libgcrypt已经有了完整的椭圆曲线基础算法,于是抱着试试看的心态基于libgcrypt测试SM2算法曲线,苍天保佑,这次的惊喜没有变成惊吓,实验结果与SM2规范一致。

第四回,libgcrypt中的ECC算法是个通用的算法,实现藕合度低。于是有了一个想法,可以尝试先在libgcrypt中实现SM2,小试牛刀之后再把这一套东西全部移植到内核,进一步推进到社区,看起来这也是能被社区接受的方式。有了计划后,索性摆个安逸çš„造型,庄严肃穆地将双手放在键盘上,让思维随着手指自然流淌,接下来的开发调试就比较顺利了,很快便有了公钥算法的四件套:加密,解密,签名,验签。一鼓作气把这些实现提交到了libgcrypt社区,经过两轮的review再修改之后,最终SM2算法作为ECC的一个子算法被社区接受,这里要感谢libgcrypt的maintainer之一的NIIBE Yutaka,耐心友好,对中国传统文化也很了解。整体过程比较顺利,表过不提。附上相关commit:

http://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgcrypt.git;a=search;s=Tianjia+Zhang;st=author

第五回,趁热打铁,由于内核中的 lib/mpi 库是一个较老的版本并且是为RSA服务的,相对于libgcrypt中的mpi,是一个阉割的版本,需要移植缺失的函数以及ECC算法,这没什么技术难度,却也是一个精细活,工作量也不小。在实践中,把实现SM2的过程中所缺失的东西都移植过来,很快便有了相应的SM2算法和国密证书的实现。再经过几轮打磨,并做了充分的测试后,就有了最初的这组patch:https://lkml.org/lkml/2020/2/16/43

第六回,中国古语曰过,一鼓作气,再而衰,三而竭,事情的进展再次遇到阻碍。Linux内核比不得专用的密码学库,对于这么一个不怎么知名的算法,社区并没有表现出什么兴趣,甚至鲜有人问津,最终以没有实际应用场景而被拒绝。事情当然不能就这么结束,考虑到代码量大,maintainer review意愿低,果断裁剪掉了SM2的加解密和签名,只保留了支持国密证书必要的验签功能,后来陆陆续续又做了一些小修小补,同时给IMA的upstream做了国密算法的增强以便将国密功能在IMA场景的应用作为实际案例。同时,随着跟相关开发者和maintainer不断的软(si)磨(chan)硬(lan)泡(da),不断地发送新的patch,最后甚至都摸透了maintainer习惯性的回复时间和patch的合入规律,持续地缓慢推进SM2进入社区的步伐。这期间没有波澜壮阔的故事,也没有狗血的剧情,balabalabala……,省略while (1) {...}循环。

第七回,年过中秋月过半, 历时半年多时间,SM2早已不是那个最熟悉的娃,不知不觉patch也更新到了v7版本。中秋月圆之夜向来都是有大事要发生的。是夜,一个盖世英雄,头顶锅盖,腰缠海带,脚踩七彩祥云飞过来了,SM2终于等到了它的至尊宝。言归正传,这个版本的patch最终被社区接受,目前已经merge到了Linux主线的5.10-rc1:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=author&q=Tianjia+Zhang

,如不出意外会在5.10内核版本中正式release。

libgcrypt 全面支持国密算法

img

后来有幸在某个机缘巧合之下,在libgcrypt中实现了SM4。作为国密开发过程的一个附属产物,目前libgcrypt已经全面支持了国密算法SM2/3/4,这些实现都会在下一个版本1.9.0正式release。其中SM3由相关同事在2017年开发。

ima-evm-utils 支持SM2-with-SM3国密签名

img

内核已经支持了SM2和国密证书,作为IMA完整性签名的用户态工具,ima-evm-utils对国密的支持当然不能落下,附上相关的commit:

https://sourceforge.net/p/linux-ima/ima-evm-utils/ci/ceecb28d3b5267c7d32c6e9401923c94f5786cfb/log/?path=

已知问题

img

当下SM2还有一些问题需要注意:

  • SM2 X509证书中没有为SM2公钥算法定义独立的OID标识,目前是识别OID_id_ecPublicKey标识默认当作SM2

  • SM2规范没有为推荐的椭圆曲线参数定义OID标识,这也导致SM2算法仅有一个默认的椭圆曲线参数

  • SM2规范中对消息签名时,除了要计算消息自身的SM3,同时SM2椭圆曲线参数和公钥都要参与到SM3的计算中来,SM2私钥签名是对最终的哈希结果做签名,这一规范定义是有点另类,这是与国际通用算法的一个主要差异:

img

正常情况下,X509证书解析与算法都被实现为独立的模块。正是由于SM2的这个规范会导致实现上的强藕合:X509证书验证时需要计算证书中tbs的SM3哈希,这个哈希同样需要椭圆曲线参数以及公钥数据,而这些数据是一次完整SM2验签过程中的临时数据,目前的内核中并没有提供这样的回调机制(当然这是SM2的特殊情况),这就把X509证书解析与SM2算法强绑到了一起,没法解藕。这也导致了应用该功能的一点限制,SM2只能支持builtin编译(Y),而不支持编译成模块(M),让X509在编译时就知道已经支持SM2,才能正常验签国密证书。从实现上看,也有一些动态加载SM2模块获取获取函数指针的方法,相比于框架层的支持,都不是很友好。

  • IMA签名在计算文件哈希的时候,内核是直接计算文件哈希的,这块并没有针对是否使用SM2签名而做特殊处理(指上图中的增加Za值)。当下内核做的IMA国密签名验证的支持,同时也支持了ima-evm-utils的国密sm2+sm3签名(依赖最新的openssl),目前这块都是直接计算文件哈希,没有加Za值,这也是当下最优的方案。需要说明的一点是,Za是国密签名以及验签里要求的,只是签名验签的流程里需要,但是国密这个流程跟目前主流的算法是相悖的,如果要支持,内核和ima-evm-utils工具都需要较大修改,内核要涉及到架构修改,社区也不愿意接受,所以目前就按主流方式支持了sm2+sm3的IMA签名。

总而言之,言而总之两条:

  • 要支持国密证书验证,SM2要么不编译,要么必须builtin编译,不支持编译成module。当然了,SM2作为一个非对称算法,只签名一个Hash或者基于国密的IMA验证,并没有这个限制

  • IMA签名工具ima-evm-utils以及内核计算文件SM3哈希所用的国密算法没有加Za,这个是与规范的一点差异

致谢

img

  • 感谢相关同学在开发过程中所做的测试工作,技术支持以及在openssl所做的大量的国密支持工作

  • 感谢社区的热心开发者,NIIBE Yutaka,Gilad Ben-Yossef,Vitaly Chikunov,Jussi Kivilinna,Herbert Xu

招贤纳士

img

在这里可以做场景落地,也可以做开源社区贡献,更有做业界创新和一展宏图的机会!欢迎各位江湖有识之士加入阿里云基础软件部操作系统团队。

容器技术之发展简史

背景

img

云原生技术有利于各组织在**公有云、私有云和混合云*等新型动态环境中,构建和运行可弹性扩展*的应用。云原生的代表技术包括**容器、服务网格、微服务、不可变基础设施和声明式API**。

聊容器技术避不开云原生,聊云原生也避不开容器技术。容器技术和云原生就是一对双螺旋体,容器技术催生了云原生思潮,云原生生态推动了容器技术发展。从2013年docker(container)技术诞生,到2015年CNCF这个云原生领域重量级联盟便成立,这不是历史的巧合而是历史的必然。作为云原生关键技术之一的容器,从2013年诞生以来一直是行业关注的焦点之一。借用一张业界广泛引用的云原生容器技术进阶图来了解一下容器技术和云原生诞生的历史背景。

img

先让我们一起来看看容器技术发展的历史纪年表,先直观感受一下这片如火如荼的热土吧!

1979年,Unix v7系统支持chroot,为应用构建一个独立的虚拟文件系统视图。

1999年,FreeBSD 4.0支持jail,第一个商用化的OS虚拟化技术。

2004年,Solaris 10支持Solaris Zone,第二个商用化的OS虚拟化技术。

2005年,OpenVZ发布,非常重要的Linux OS虚拟化技术先行者。

2004年 ~ 2007年,Google 内部大规模使用 Cgroups 等的OS虚拟化技术。

2006年,Google开源内部使用的process container技术,后续更名为cgroup。

2008年,Cgroups 进入了 Linux 内核主线。

2008年,LXC(Linux Container)项目具备了Linux容器的雏型。

2011年,CloudFoundry开发Warden系统,一个完整的容器管理系统雏型。

2013年,Google通过Let Me Contain That For You (LMCTFY) 开源内部容器系统。

2013年,Docker项目正式发布,让Linux容器技术逐步席卷天下。

2014年,Kubernetes项目正式发布,容器技术开始和编排系统起头并进。

2015年,由Google,Redhat、Microsoft及一些大型云厂商共同创立了CNCF,云原生浪潮启动。

2016年-2017年,容器生态开始模块化、规范化。CNCF接受Containerd、rkt项目,OCI发布1.0,CRI/CNI得到广泛支持。

2017年-2018年,容器服务商业化。AWS ECS,Google EKS,Alibaba ACK/ASK/ECI,华为CCI,Oracle Container Engine for Kubernetes;VMware,Redhat和Rancher开始提供基于Kubernetes的商业服务产品。

2017年-2019年,容器引擎技术飞速发展,新技术不断涌现。2017年底Kata Containers社区成立,2018年5月Google开源gVisor代码,2018年11月AWS开源firecracker,阿里云发布安全沙箱1.0。

2020年-202x年,容器引擎技术升级,Kata Containers开始2.0架构,阿里云发布沙箱容器2.0….

整理容器技术近20年的发展历史,大致可以将其分为四个历史阶段,下文将详细介绍这四个历史阶段。

img

技术萌芽期

img

容器技术需要解决的核心问题之一运行时的环境隔离。容器的运行时环境隔离,目标是给容器构造一个无差别的运行时环境,用以在任意时间、任意位置运行容器镜像。由于docker的布道,大家习惯性认为容器的运行时环境隔离就是OS虚拟化,或则容器等于namespace + cgroup + 安全防护机制。我不太赞同这种看法,这个只是一段历史时期、一种容器运行时的实现技术,还有很多种其它可能的技术方案来实现容器运行环境。所以,回到需求的本源:容器需要运行时隔离技术来保证容器的运行环境符合预期。习惯上,大家把这种实现容器隔离技术的组件叫做容器运行时。

从另外一个角度看,容器隔离技术解决的是资源供给问题。为啥需要容器隔离技术来解决资源供给问题呢?成也萧何,败也萧何!摩尔定律实在太过强大,它让我们有了越来越多的计算资源可以使用。10年前做小型机时,小型机的典型规格是32路8核CPU,现在一台4路PC服务器计算能力都超过10年前的小型机服务器。小型机的典型用法是把整机切分为多个分区使用。观察当下云服务硬件发展趋势,越来越有熟悉的感觉,我们在把小型机相关技术“军转民”。现在我们一台PC服务器拥有了非常强大的、能和十年前小型机媲美的计算能力,巧合的是当下PC服务器的典型用法也和十年前的小型机用法类似,切割为1-8vCPU的虚拟机/容器使用。

为什么人们总是习惯于把一个大的服务器资源切分为小的分区使用而不是研发能够充分发挥大型服务器整机计算能力的软件呢?个人认为背后有两个制约因素:

  • 待解决问题本身内在的并行度有限。随着多核多处理器系统的日益普及,IT行业从2004年开始进行串行编程到并行编程的升级改造。开始阶段针对特定行业应用的并行化改造效果非常明显,但是后来发现随着并行度提高改造成本越来越大、收益却越来越低。受阿姆达尔定律制约,解决特定问题的并行度超过一定临界点之后收益将逐渐变小。所以一味提高系统并行度并不是经济的做法。

  • 人类智力有限。受人类智力限制,系统越复杂、并行度越高,软件越容易出故障,软件维护代价成指数级增长。所以,从软件工程看,大家也趋向于接口化、模块化、单元化的软件架构设计,尽量控制软件的复杂度,降低工程成本。

从经验看,1-8个CPU的并行度是软件工程的舒适区,这个也是容器化、微服务等技术背后的驱动因素之一。

有点跑题了。。。总之,基于隔离的资源供给不是伪需求。对于软件运行环境的隔离要求,从操作系统出现之初就有了。多任务分时操作系统和进程虚拟地址都是为了解决多个任务运行在同一台主机上的资源共享问题,让每个进程都以为自己独占主机。当然仅仅是进程隔离是远远不够的。纵观当前的资源隔离技术,我们大致可以将资源隔离技术分成5类:

img

  • 进程隔离。OS以进程作为Task运行过程的抽象,进程拥有独立的地址空间和执行上下文,本质上OS对进程进行了CPU和内存虚拟化。但是进程之间还共享了文件系统、网络协议栈、IPC通信空间等多种资源,进程之间因为资源争抢导致的干扰很严重。这个层级的隔离适合在不同的主机上运行单个用户的不同程序,由用户通过系统管理手段来保证资源分配与安全防护等问题。

  • OS虚拟化。OS隔离,也就是大家常说的操作系统虚拟化(OS virtualization),是进程隔离的升华版。进程隔离是为每个进程实现了单独的地址空间及CPU上下文,OS隔离则是利用操作系统分身术为每一组进程实例构造出一个独立的OS环境,以进一步虚拟化文件系统、网络协议栈、IPC通信空间、进程ID、用户ID等OS资源。OS隔离需要解决三个核心问题:独立视图、访问控制及安全防护。Chroot、Linux namespace机制为进程组实现独立视图,cgroup对进程组进行访问控制,而Capabilities、Apparmor、seccomp等机制则实现安全防护。当然,OS是一个非常复杂、动态变化的系统,OS分身术虽然让进程组感觉有了独立的OS,但是真实实现还是一个OS实例,所以整体防护能力还是堪忧。

  • 硬件虚拟化。OS虚拟化是实现OS内核的分身术,而硬件虚拟化则是实现硬件设备的分身术。硬件虚拟化技术的出现,让同一个物理服务器上能够同时运行多个操作系统,每个操作系统都认为自己在管理一台完整的服务器。不同操作系统之间是严格隔离的,Guest操作系统对硬件的访问都是受VMM或CPU的严格监管的。硬件虚拟化既有很好的安全性,也有很好的隔离性,缺点就是引入的硬件虚拟化层导致了额外的性能开销。

  • 硬件分区。这个是传统小型机体系采用的资源分隔技术,就是从硬件或固件层彻底把一台大型服务器分隔为多个硬件单元,从而获得最高等级的安全性和隔离性。但是小型机作为一个逐步没落的技术路线,其不足之处还是显而易见的:资源分隔粒度不灵活、系统成本偏高、系统可扩展性受限。

  • 语言运行时隔离。对于Java、nodejs等需要language runtime的managed language,我们还有一个选项,就是在language runtime里实现隔离。针对函数计算等云原生服务,理论上在语言运行时实现隔离机制是最优路径。但是这条路线目前实现上还有不少现实的制约,所以目前多数函数计算还是采用的容器/VM技术来实现的隔离。

在OS虚拟化这条技术路线上,最大的技术贡献来源于Google。2003-2006年,Google陆续发布的“三驾马车”,奠定了大数据计算的框架,随后进一步创造了“云”的概念。也是从这时期开始,进程隔离技术进入了一个更高级的阶段。在 Google 提出的云计算框架下,被隔离的进程不仅仅是一个与外界隔绝但本身却巍然不动的 Jail,它们更需要像一个个轻便的容器,除了能够与外界隔离之外,还要能够被控制与调配,从而实现分布式应用场景下的跨平台、高可用、可扩展等特性。2006年,Google推出Process Containers,用来对一组进程进行限制、记账、隔离资源(CPU、内存、磁盘 I/O、网络等)。由于技术更加成熟,Process Container 在 2006 年正式推出后,第二年就进入了 Linux 内核主干,并正式更名为 Cgroups,标志着 Linux 阵营中“容器”的概念å¼€始被重新审视和实现。在 2008 年,通过将 Cgroups 的资源管理能力和 Linux Namespace (命名空间)的视图隔离能力组合在一起,一项完整的容器技术 LXC (Linux Container)出现在了 Linux 内核中,这就是如今被广泛应用的容器技术的实现基础。

总体看,在2013年docker被发明以前,Linux操作系统已经大体上解决了容器核心技术之一的运行环境隔离技术,或者说Linux OS虚拟化技术已经基本上成型了。虽然容器运行环境隔离技术已经基本就位,我们仍需等待另外一项关键技术才能迎来容器技术的腾飞时刻。

技术迸发期

img

2013年之前,云计算行业一直在为云原生的正确打开姿势而操心。Platform as a Service(PaaS)看起来是个有前途的方向。2006年Fotango公司发布的Zimi服务,可以说是PaaS行业的鼻祖,具有按使用付费、免运维(Serverless)、API化配置和服务等典型云原生的特征;2008年Google推出GAE;2011年Pivotal发布Cloud Foundry。这些早期的PaaS平台进行了非常有益的探索,推动了云计算生态的健康发展,但是这些早期探索技术并没有形成大的行业趋势,而是局限在一些的特定的领域。直到Docker开源,大家才如梦方醒,原来不是方向不对,而是应用分发和交付的手段不行。

Docker真正核心的创新是容器镜像(docker image),一种新型的应用打包、分发和运行机制。容器镜像将应用运行环境,包括代码、依赖库、工具、资源文件和元信息等,打包成一种操作系统发行版无关不可变更软件包。

  • 容器镜像打包了整个容器运行依赖的环境,以避免依赖运行容器的服务器的操作系统,从而实现“build once,run anywhere”。

  • 容器镜像一但构建完成,就变成read only,成为不可变基础设施的一份子。

  • 操作系统发行版无关,核心解决的是容器进程对操作系统包含的库、工具、配置的依赖,但是容器镜像无法解决容器进程对内核特性的特殊依赖。这个在实际使用容器的过程中也经常跳进这个大坑:

Docker的宣传口号是“Build,Ship and Run Any App,Anywhere”。我们已经理解了docker通过container image解决“Run Anywhere”的机制,那么“Run Any App”是如何实现的呢?其实也是依赖container image,用户可以打包任何容器进程所依赖的环境,而不用改造应用来适配PaaS定义的运行环境。真是“Run Any App”一举打破了PaaS行业面临的困境,创造出了无限的可能性,大力推动了云原生的发展。让我们一起来向这个伟大的创意致敬!

img

至此,容器技术体系已经解决了最核心的两个问题:如何发布软件如何运行软件腾飞时刻即将到来。2014年前司前老板对我说“别成天搞Linux kernel了,要不你看看docker?” 经过短暂的调研,我给了前老板一个简单而清晰的回答,“无它,唯打包工具尔!”因为这个回答,云原生为我打开的一扇大门就悄悄关上了。回想一下历史,有时也挺懊悔的,因为自己太年轻而没有看清楚容器技术 + 编排系统的威力,更没有体会到云原生即将到来的气息!

Docker作为一个单机软件打包、发布、运行系统,其价值是非常巨大的;但是仅仅将docker技术局限在单机范围不能发挥这个创新技术的最大价值,自然下一步业界希望基于docker技术构建一个云化的集群系统,来对业务容器进行编排管理。

聊到容器编排系统,我们需要从Google聊起。2008年,Google 基于 LXC 推出首款应用托管平台 GAE (Google App Engine),首次把开发平台当做一种服务来提供。GAE 是一种分布式平台服务,Google 通过虚拟化技术为用户提供开发环境、服务器平台、硬件资源等服务,用户可以在平台基础上定制开发自己的应用程序并通过 Google 的服务器和互联网资源进行分发。Google 在 GAE 中使用了一个能够对 LXC 进行编排和调度的工具 —— Borg (Kubernetes 的前身)。Borg 是 Google 内部使用的大规模集群管理系统,可以承载十万级的任务、数千个不同的应用、同时管理数万台机器。Borg 通过权限管理、资源共享、性能隔离等来达到高资源利用率。它能够支持高可用应用,并通过调度策略减少出现故障的概率,提供了任务描述语言、实时任务监控、分析工具等。如果说一个个隔离的容器是集装箱,那么 Borg 可以说是最早的港口系统,而 LXC + Borg 就是最早的容器编排框架。

2013年docker推出之后迅速席卷全球,2014年Google基于内部使用的Borg系统创建了开源项目Kubernetes(简称K8S),用于解决大规模集群的容器部署、运行、管理等问题。Kubernetes在容器的基础上增加了一层的新的管理抽象Pod,以便更好地利用容器进行应用的功能模块切分。得益于 Google 在大规模集群基础设施建设的强大积累,脱胎于 Borg 的 K8S 很快成为了行业的标准应用,堪称容器编排的必备工具。

作为回应,Docker公司在2015年发布的Docker 1.12版本中也加入了一个容器集群管理系统Docker swarm,以及配套的Docker machine、Docker Compose等工具,力图构建完善的容器编排系统,和Kubernetes展开正面竞争。从此,容器江湖分为两大阵营:Google派和Docker派;而容器编排系统则是Kubernetes,Docker Swarm和Apache Mesos三国并立。各大派系的竞争愈演愈烈,逐渐延伸到行业标准的建立之争。让我们一起来回忆一下这段风起云涌的江湖历史吧!

2013年Docker公司推出docker之后,紧接着CoreOS 应运而生。CoreOS 是一个基于 Linux 内核的轻量级操作系统,专为云计算时代计算机集群的基础设施建设而设计,拥有自动化、易部署、安全可靠、规模化等特性。其在当时有一个非常显眼的标签:专为容器设计的操作系统。借着 Docker 的东风,CoreOS 迅速在云计算领域蹿红,一时间,Docker + CoreOS 成为业内容器部署的黄金搭档。同时,CoreOS 也为 Docker 的推广与社区建设做出了巨大的贡献。然而,日渐壮大的 Docker 似乎有着更大的“野心”。不甘于只做“一种简单的基础单元”的 Docker,自行开发了一系列相关的容器组件,同时收购了一些容器化技术的公司,开始打造属于自己的容器生态平台。显然,这对于 CoreOS 来说形成了直接的竞争关系。2014 年末,CoreOS 推出了自己的容器引擎 Rocket (简称 rkt),试图与 Docker 分庭抗礼。rkt 和 Docker 类似,都能帮助开发者打包应用和依赖包到可移植容器中,简化搭环境等部署工作。rkt 和 Docker 不同的地方在于,rkt 没有 Docker 那些为企业用户提供的“友好功能”,比如云服务加速工具、集群系统等。反过来说,rkt 想做的,是一个更纯粹的业界标准。

上面这段材料引至于“从虚拟化到云原生——容器技术的发展史”,为什么大段大段地引用这部分材料呢?这里面最关键的脉络是由于技术公司之间的商业竞争,在竞争合作之间寻找平衡从而导致了标准规范的诞生,而标准规范的诞生是整个云原生生态最重要的基石

容器引擎(docker vs rocket)、容器编排(Docker swarm vs Kubernetes vs Apache Mesos)的相互竞争的结果就是大家坐下来谈接口标准。2015年6月,Docker带头成立OCI,旨在“制定并维护容器镜像格式和容器运行时的正式规范(OCI Specifications)”,其核心产出是OCI Runtime Spec(容器运行时规范)、OCI Image Spec(镜像格式规范)、OCI Distribution Spec(镜像分发规范)。所以OCI组织解决的是容器的构建、分发和运行问题。一个月之后,Google带头成立了Cloud Native Computing Foundation(CNCF),旨在“构建云原生计算 —— 一种围绕着微服务、容器和应用动态调度的、以基础设施为中心的架构,并促进其广泛使用”。所以CNCF组织解决的是应用管理及容器编排问题。这两个围绕容器的基金会对云原生生态的发展发挥了非常重要的作用,二者不是竞争而是相辅相成,共同制定了一系列行业事实标准。这些行业事实标准的确立,各行业注入了无限活力,基于接口的标准的具体实现不断涌现,呈现出一片百花齐放的景象。

image.png

其中,与容器相关的最为重要的几个规范包括:CRI、CNI、CSI、OCI Distribution Spec、OCI Image Spec、OCI Runtime Spec和Shimv2。其中的CRI、OCI Image Spec、OCI Runtime和Shimv2规范和阿里云沙箱容器关系非常密切。

所以,非常感谢这个云原生、容器技术迸发的黄金期,一群有创意的人走到一起共同创造了这几个关键的规范,为各个厂商提供各具特色且遵循规范的技术实现提供了可能性。

商用探索期

img

经过5年的技术发展期,容器技术基本成熟,云原生体系也具雏型。从2017年开始,各大云厂商开始试水容器服务及进步的云原生服务。从目前的商业形态看,容器相关的公共云服务大致可以划分为三种形态:

  1. 通用容器编排服务。在容器编排系统三国杀结果出来以前,基于多方下注策略构建的容器编排服务系统。其中AWS是自研的编排系统,Azure的ACS同时支持Docker Swarm、DC/OS和Kubernetes,阿里云ACS则是支持Docker swarm和Kubernetes。Google和华为则是坚定支持Kubernetes而未推出支持其它容器编排系统的容器服务。随着Kubernetes一统容器编排江湖,这条路线的容器服务日渐式微,Azure更是在今年初直接终止了ACS服务。

  2. Kubernetes容器编排服务。Google是理所当然最早试水Kubernetes容器编排服务的大厂,也较早开展了K8S容器编排服务。随着2017年各大厂在CNCF这张谈判桌上达成了Kubernetes兼容性认证流程,Kubernetes编排服务市场迎来一轮大爆发,到2018年各大云厂商的K8S容器编排服务就完整就位了。

  3. Serverless容器实例服务。从2017年开始,行业开始试水Serverless容器实例服务,把用户从维护容器基础设施的繁重任务中解放出来从而聚焦业务本身。Google Cloud Run核心目标是支持Knative,所以其使用形态上附加了不少约束条件。

img

从上图可以看出,从2014年开始探索公共云容器服务,特别是经过2017-2018年这两年的抢跑期,容器服务的基本商业形态已经比较明晰了。发展态势可以概括为:

  • 行业对容器化的接受程度已经很高,容器化普及率也是逐年提升。

  • 容器编排系统已经一战定江山,K8S成为事实上的容器编排之王。

  • Serverless容器实例服务受到市场的欢迎,客户群体日益扩大。

  • 长期看托管容器编排服务和Serverless容器实例服务将长期共存,协同满足客户对服务成本和弹性能力的需求。

商用模式探索期间,核心目标是快速试错引导和确认客户需求,构建适用的产品形态。这个期间的产品技术架构的构建思路是利用现有成熟技术快速搭建商用形态,在试错过程中不断前行。

其中,容器编排托管服务节点级的典型架构是利用IaaS系统生成VM,然后在VM里面部署kubelet、docker、containerd、runC等容器服务组件,也就是VM + 容器的技术架构。一个VM可以承载同一个用户的多个容器/Pod实例。而Serverless容器实例服务的节点级架构更直接,在一个VM里面只部署一个容器/Pod实例,从而实现Serverless。这种短平快的打法快速推进了商用模型的探索,起到了非常重要的历史作用,但是其在弹性能力、部署密度、资源成本方面的历史局限性还是很大的。

img

商用拓展期

img

到2019年,容器服务的商业形态以及市场趋势已经很明显了,行业整体进入了商业拓展阶段,对外宣传吸引更多的客户群体,对内苦练内功提升产品技术竞争力,行业正在经历从“有”到“优”的技术升级。行业正在经历这个技术升级的历史阶段,还谈不上结论,只能一起来聊聊趋势及预判。本系列专题的关注点是容器隔离技术,所以先不聊商业拓展和容器编排而聚焦于容器引擎技术发展趋势。到现在为止,我们大体上可以把容器引擎技术划分为两代:

  1. Container on VM。也就是按照分层设计思路,通过IaaS + PaaS的架构构建容器服务,这个是商用探索阶段的典型架构。基于各大云厂商成熟的IaaS基础设施生产虚拟机,在虚拟机里面部署容器服务组件。这种架构采用的是lift and shift策略,把容器服务的运维责任从用户转移到云厂商。采用和用户相同的软件组件,只是转移运维责任,有利于引导客户逐步上云、接受云原生思维。但是这个时期云厂商提供的服务是单纯的运维托管,相对用户自建容器服务并没有太明显的技术优势,甚至受多租户隔离的限制部分使用体验还不如用户自建容器服务。

  2. Container with hardware virtualization。如果沿用Container on VM的分层设计架构,云厂商很难构建独有的技术优势。对于Serverless容器实例服务,服务交付平面已经从IaaS的硬件接口上移到OS Syscall,所以不要遵循VM + 容器的分层设计思路。我们需要从需求本源出发,容器服务需要高性能、强隔离、够安全和低成本的容器引擎。当前行业研发热点之一就是如何构建这样一个容器引擎,具体技术思路请留意后续系列文章。

小结

img

总结来看,容器服务生态大概经历了四个阶段,分别解决或试图解决不同的问题:

  1. 技术萌芽期:解决了容器运行环境的隔离问题
  2. 技术迸发期:解决了软件分发及容器编排问题
  3. 商用探索期:确认了容器的商用服务形态
  4. 商用拓展期:扩大适用场景和部署规模,通过技术创新提升产品竞争力

闲言碎语

img

聊了这么多历史,让我们再来闲聊一下docker这个公司和docker这门技术吧!

2019年11月13日,私有云基础设施公司Mirantis在其官方博客宣布,收购Docker公司企业级业务,包括接管它的700多个客户,这标志着Docker公司从2013年开始的商业化探索彻底失败。在不了解容器发展历史的人看来,这种结果很难理解,Docker是容器热潮的开创者,容器则是这一轮云计算技术演进的开启者,为什么明明站在风口上了,却仍然飞不起来?

其实,Docker今天的命运,在4年前就决定了。2014年Kubernetes发布后,迅速吸引了包括Redhat在内的一批重量级成员,并在一年之后迅速发布Kubernetes 1.0以支撑正式商用。作为回应Docker公司主导成立了OCI,旨在为容器镜像格式和运行时制定一个开放标准,从而继续占据容器生态的话语权。但是2015年7月CNCF成立之后,迅速弯道超车开辟新的战场,主攻容器编排与应用管理。随后2016年Kubernetes社区制定了容器运行时的接口规范CRI,只要实现这个CRI规范的容器运行时就可以和K8S生态对接,从引发了容器引擎的研发热潮。cri-containerd,cri-o,frakti等引擎不断涌现,加上原有的rkt引擎,docker变成了容器引擎芸芸众生中的一员。从哪儿来到哪儿去,docker又回到了最初的状态,一个单机版软件打包运行工具,基本上完美错过了云原生浪潮。

但是在相当长的时期内,docker这个客户端容器管理工具(UI)还是会长期存在的,毕竟强大的用户群体在哪儿。但是在云服务厂商的技术栈中,docker的地位会越来越弱,逐步被K8S专用的容器引擎替代。虽然现在docker的群众基础依然强大,但是星星之火已经点燃,趋势已然显现,剩下的只是时间问题!


参考文献

  • Cloud Native and Container Technology Landscape
  • A Brief History of Containers: From the 1970s Till Now
  • 从虚拟化到云原生——容器技术的发展史
  • 为什么说2019,是属于容器技术的时代?
  • 阿里巴巴在安全容器上的实践与探索
  • 安全容器在边缘计算场景下的实践
  • 展望2020:传统容器已死,安全容器将成为云原生标配

img

面对疾风吧!io_uring_优化_nginx_实战演练

引言

io_uring是Linux内核在v5.1引入的一套异步IO接口,随着其迅速发展,现在的io_uring已经远远超过了纯IO的范畴。从Linux v5.3版本开始,io_uring陆续添加了网络编程相关的API,对用户提供sendmsg、recvmsg、accept、connect等接口的异步支持,将io_uring的生态范围扩大到了网络领域。

另外从Linux v5.7开始,io_uring对这些异步接口提供FAST POLL机制,用户无需再使用像select、event poll等多路复用机制来监听文件句柄,只要把读写请求直接丢到io_uring的submit queue中并提交,当文件句柄不可读写时,内核会主动添加poll handler,当文件句柄可读写时主动调用poll handler再次下发读写请求,从而减少系统调用次数提高性能。

上一篇我们初探了 io_uring 用于网络的编程模型以及 echo server benchmark 下的性能表现,这篇文章我们将基于通用应用 nginx 实战。

Nginx io_uring 代码优化

Nginx是一款轻量级的Web服务器、反向代理服务器,由于它的内存占用少,启动极快,高并发能力强,在互联网项目中广泛应用。

img

从架构上看,Nginx由一个master和多个worker进程组成,多个worker之间不需要加锁,独立处理与client的连接和网络请求。worker是一个单线程大循环,这与上一篇“你认为 io_uring 只适用于存储 IO?大错特错!”文章中描述的 echo server 模型基本一致。

基于event poll的编程模型

event poll是Nginx在Linux下的默认事件模型。

img

event poll事件模型把listen fd以及新建连接的sock fd都注册进event poll中,当这些fd上有数据可读时,等待在epoll_wait()的worker进程会被唤醒,调用相应的回调函数进行处理,这里的recv、writev请求都为同步请求。

基于io_uring的编程模型

前面提到,io_uring的FAST POLL机制允许数据在未ready的情况下就直接下发,不需要再把普通连接的fd注册进event poll。另外这里的读写请求通过io_uring异步下发,处理流程大致如下:

img

事实上,accept()也可以采取FAFST POLL机制,无需等待listen_fd数据可读就直接下发,以减少系统调用次数。但在调试过程中发现这样accept()失败概率大大增加,而每次失败的accept()都会带来一次无效的sock内存申请和释放,这个开销较大,因此依然采用类似event poll的方式来侦听listen fd。后续针对这块可以做一些优化。

测试结果

测试环境

  • 测试机器
    • CPU: Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz 64逻辑核
    • server cmdline添加:mitigation=on
  • nginx配置
user root;
http {
    access_log  off;
    server {
        access_log  off; // 关闭access log,否则会写日志,影响测试
        location / {
            return 200;  // 不读本地文件,直接返回200
        }
    }
}
  • benchmark 使用轻量级HTTP性能测试工具wrk进行压测。

  • 测试命令

    长连接 wrk -c $connection -t $thread -d 120 $url
    短连接 wrk -c $connection -t $thread -H "Connection: Close" -d 120 $url
    

测试结果

长连接

  • connection=1000,thread=200, 测试server上不同worker数目性能。

worker数目在8以下时,QPS有20%左右的提升。随着worker数目增大,CPU不成为瓶颈,收益逐渐降低。

  • server单worker,测试client端不同连接数性能(thread取默认数2)。

可以看到单worker情况下,500个连接以上,QPS有20%以上的提升。从系统调用数目上看,io uring的系统调用数基本上在event poll的1/10以内。

短连接

  • connection=1000,thread=200, 测试server上不同worker数目性能。

短连接场景,io uring相对于event poll非但没有提升,甚至在某些场景下有5%~10%的性能下降。究其原因,除了io uring框架本身带来的开销以外,还可能跟io uring编程模式下请求批量下发而带来的延迟有关。

总结及下一步工作

从笔者目前的测试来看,io_uring在网络编程方面的优化更适合长连接场景,在长连接场景下最高有20%多的提升。短连接场景还有待优化,主要考虑以下两方面:

  • io uring本身框架开销的优化,当然这个优化对长连接同样适用。
  • 针对短连接的优化,如针对accept()请求,先检查是否有数据可读,避免无效内存申请释放;多个accept()一起下发等。

nginx 和 echo server 等优化实践相关内容(包含源代码),我们都已经在 OpenAnolis 社区高性能存储 SIG 开源(openanolis.org)。也欢迎大家积极参与讨论和贡献,一起探索 io_uring 的高性能之路。