技术人攻略访谈二十九:平行世界守护者

吴峰光

文:Gracia (本文为原创内容,部分或全文转载均需经过作者授权,并保留完整的作者信息和技术人攻略介绍。Sai对本文亦有贡献。)

导语:本期采访对象吴峰光,任职于Intel开源技术中心。从第一次向内核社区提交patch,到成为全职的开源贡献者,峰光投身于开源领域已将近10年。作为核心的内核代码贡献者,他有独立维护的代码tree,可以直接向Linus Torvalds提交patch,并每年受邀参加Kernel Summit峰会。在庞大的Linux开发者社区里,能达到这几点的,全球范围内不过百人。

诞生于1991年的Linux,是整个开源世界的核心,以此为基础孕育出互联网的繁荣。历经二十几年的发展,Linux的影响力早已超越操作系统核心本身,分散在全球各地的数千名开发者,通过网络协作搭建心目中的理想国,竟能魔术般地创造出超越商业的力量。这不仅是软件工程的奇迹,更是对传统人类社会组织的重构。《大教堂与集市》这本书中,对Linux的这种颠覆性模式做了详尽阐述:把单个黑客的自我实现紧密绑定在通过持续合作才能达成的目标上,形成开放和进化式的生态系统。在这个扁平的无政府主义世界中,代码的完美程度是获取声望的唯一武器。纯粹理想主义气质的市集,最终形成了宏伟的大教堂,甚至影响了商业世界的走向,这其中究竟遵循什么样的法则?从峰光的分享中,我们得以略窥一二。

或许是虚拟世界过于精彩,在现实中,峰光过得至为简朴。更为难得的是,他遇到了志趣相投的另一半,一位名叫Sai的奇女子。婚后,他们在上海开始了“居无定所”的生活:两人都可远程办公,省却了上下班路上的通勤,跟据每天的活动范围换不同宾馆住,当然基本都远离市区,开一辆外地牌照的车,仅一个后备箱就可以容下全部行李。听上去难以置信,他们却乐在其中,像是生活在平行世界,精神上的富足远比对物质的追逐来得重要。不知为何,每当想起像峰光这样的一群人在守护着Linux,我对现实世界就多了一份信心。

技术人攻略:你从什么时候开始接触内核开发?

我大学就读于中科大自动化系,在那里从本科一直念到博士。大三开始接触Linux,参加学校的Linux用户协会。博士期间,实验室几个导师都是数学系出身,本来想跟随导师做随机过程方向的理论研究。但实验室有项目需要用Linux,我在这方面比较熟,承担起了开发和服务器维护的工作,自然而然转向了应用领域。

博士期间接触到一个863项目,需要搭建高性能的流媒体服务器,性能瓶颈却卡在磁盘I/O上。优化过程中,我花了一个多月时间,顺藤摸瓜分析到系统底层,把内核I/O路径整个看了一遍,开始对I/O预读算法做改进。预读是一种启发式算法,通过预测应用程序的读行为提升性能。流媒体不同于一般的顺序读,更像同一个应用程序在做两个区域的并发顺序读。完成预读算法改进之后,我想让大家都享受到这个好处,于是写了组patch提交给社区。由于是新手,完全不知道内核代码提交的流程和规范,花了一年多时间,一直更新到V12才被接收,由此走上了内核开发这条路。

技术人攻略:听说你毕业之后就进入Intel全职做开源,都做了哪些事情?

博士毕业进入Intel,在这里待了5年多。Intel上海的开源团队有两、三百人,从最底层的内核,到Hadoop、浏览器、HTML5、Android等关键开源技术都有所覆盖。

一开始,我的工作是博士期间项目的延续,继续完善I/O预读,后来开始做I/O回写。从2012年到现在的主要工作是搭建了一套Linux内核测试服务。Linux应用场景广泛,从嵌入式设备到超级计算机都在用,测试的难度很高。I/O回写的功能做了两年,小部分时间花在做算法上,大部分时间都花在了各种场景的测试上,测试数据作图形化分析,前后浏览了数万张图片,据此发现问题和改进算法最后提交的patch代码只有1000余行。

关于测试的复杂性可以举个例子,比如I/O预读,不同应用程序有不同读的大小、模式、并发度,还要考虑系统的内存压力。I/O回写更复杂,不仅要测试不同应用程序,还要测每一个文件系统。Linux的文件系统很多,包括ext4、XFS、Btrfs等。文件系统下面还有不同的存储介质,磁盘、USB、SSD、NFS、iSCSI。从上到下,每一层都有一堆变数。甚至连内存大小都有关系,因为弹性缓存对内存敏感。

技术人攻略:这个测试服务能解决什么问题?有哪些特点?

当时内核组想做些基本的内核测试,确保发出去的patch至少可以被编译和启动。从追求效益最大化的角度出发,干脆就把目标用户锁定为整个社区,开发了一套测试云服务。做测试不像开发新功能那样酷,一开始很难找到志同道合者,整个测试系统从一个人、一台机器开始。做的过程中想尽办法,在公司内部和社区去争取资源,到现在已经有了几十台机器,团队成员也有了好几个人。

Linux的bug有两种,一种是新bug,一种是Regression bug。新bug一般伴随新功能产生,用户愿意承担;Regression bug则要严重得多,原本正常的功能,在升级之后却出现问题,这样的情况多了,用户就不愿意升级了。开发者很难有能力做特别全面的测试,看代码是否在其他地方造成Regression bug。这正是我们的测试服务可以帮助到开发者的。Linux发展到这个地步,将测试纳入正轨非常重要。

我们的测试覆盖非常全,把能找到的内核tree都加进去了,有400多棵。刚推出的时候大家很是惊喜,因为速度很快,功能强大。最大的好处是开发者什么都不用做,只管在自己的tree上开发,这边的机器人自动就把tree上的新代码拉下来,短则几分钟,长则一个小时,就能出Bug report。相当于是专业踩雷工具,踩得快,修复得快,其他人就不会踩到了。这样就把内核开发者互相之间的影响降到最低。

这套测试工具特别擅长抓Regression bug。基于Git里面的bisect命令,测试系统通过二分法定位各种Regression bug。比如3.13内核没问题,到3.14出问题了,这两个版本之间有上万个commit,如果不知道是哪个commit造成这个问题,连该找谁修复都是问题。这种漫无目的的debug要求开发者非常专业,必须对内核各个方面都非常了解,才能感知和分析哪里出了问题。但用bisect,相当于把计算机变成一个内核专家。bisect可以迅速定位问题,找出有问题的commit,自动给作者和维护者发邮件。他们是该bug最相关的人,往往第一眼就看出问题出在哪里,并了解如何修复最为妥善。

大系统各方面出问题的机会多,依赖完善的测试工具,通过降维方式,用工程方法快速定位问题,Regression bug就可以避免。这两年一直在改进这套系统,测试是没有止境的,可以不断增加覆盖和测试种类。一开始做的是内核编译,然后是内核启动测试,再到功能测试、性能和功耗测试。

技术人攻略:如何给Linux内核社区提交代码?整个社区的结构和决策过程是怎样的?

Linux内核社区的规模很大,每一个版本的代码贡献人数往往达到上千,支撑这个体系运转的,是一套完善的开发流程。组织结构最顶层是Linus Torvalds,维护mainline tree,他只接受由maintainer提交的patch。maintainer下面是sub-maintainer,再下面是普通的developer。

核心maintainer是基于长期合作在社区建立起信任和威信的一群人,大概有上百个,每人维护一棵或几棵tree,按照子系统分成CPU体系架构、网络、文件系统、I/O、内存管理,及各类驱动等领域。新代码就绪的时候,他们会给Linus Torvalds提请求,Linus认为没问题就merge。

任何人都可以提交patch,代码被接受的关键有两步,第一是有人review你的代码,第二是maintainer接收代码。提交patch之前,可以通过查询Git历史,找到对代码改动最多的人,给他发邮件,并cc给邮件列表。以确保代码能被合适的人看到和review。

maintainer和活跃开发者都可以参与review,并给出意见。在review过程中,一旦某人认可你的patch,会获得一个reviewed by的记录,表示他们同意你进Upstream。核心代码一般需要获得两个以上的reviewed by,如果你成功获取了几个reviewed by,这些参与review的人又是maintainer所信任的,那代码被接收的问题就不大了。 如果出现意见分歧,Linus Torvalds拥有最终决定权。当然实际操作中,Linus不会经常出来PK,大多问题都由maintainer搞定。但Linus时不时也会在公开的邮件列表中发飙。

Linux社区有完善的运行机制,新人想融入社区,需要多花心思,不断学习和适应。我花了一年多时间,才真正了解了社区运作的整个流程,该怎么写代码,怎么发代码,怎么跟人交互。这里面的规则,很多文档里都有,只是看文档是一回事,在实践中落实是另一回事。

内核社区的人来自全球各地,邮件是大家达成协作的主要交流方式,所以对写邮件的格式有严格的要求。中间有很多细节,比如发邮件的程序要怎么设置,要小心防止代码被邮件客户端自动换行,邮件该CC给谁,如何给别人回复邮件,如何在回复中保留相关的上下文。新人没经过锻炼,就容易出错。例如对于别人给出的review,不能采用top reply的方式回复,而必须要到邮件的原文下方,一段一段地去回复,逐条表明是否同意,不同意的话,原因是什么。社区里面review的资源十分珍贵,大家基本是在义务劳动,帮助改善你的patch。如果reviewer给出了意见,却被忽略了,是不可接受的。

公司的代码如果想进Upstream,也要遵循一套规范。建议一开始就在公开的邮件列表里声明,打算做什么?怎么做?在设计阶段就把想法提出来,并搜集大家的需求和反馈。从maintainer角度出发,他关心代码是否解决通用性问题,否则系统会越来越复杂。而且代码一旦push进Upstream,对maintainer和社区是长期维护的负担,这也是为什么代码的审核会控制得如此严格。社区曾经有过一场很大的论战,起源是Google对Android做了一些特殊扩展和优化,在市场上铺开来之后想要把代码push到内核。因为Google的做法违反了通用原则,没有一早参与社区互动和征询意见,而是木已成舟了再提交,结果是社区不可避免的提出了许多尖锐的批评。这场论战非常火爆,最后论战各方共同对代码做了一些重写和改良,社区才最后接受。

技术人攻略:Linux如此成功,得益于其独特的软件开发组织形式,你认为这种形式有哪些值得学习的地方?

从1991年到现在,Linux社区相当成功,Linus Torvalds一直在谋求更好的软件开发组织形式。以前看过一本书,里面有个话题很有趣:如果把创造出Linux的这群工程师,一开始就关到一个房间里,还会诞生Linux这个系统吗?结论是很可能不会,因为群体性的偏差会导致项目走向另外的方向。

Linux社区花了很长的时间,才进化出现有这套开发流程和体系,每条规则都是慢慢形成的。这个系统所有的流程和方法论,都适应了互联网环境下分布式的协作方式,既能够让大家各有贡献,又不会造成太大损耗。虽然缺乏面对面的交流,但对于深层、有挑战性的问题,每个人各自静下心来思考出一套深刻和周密的解决办法,又比交流重要得多。网络协作客观上有利于保持大家独立思考的空间。如果成为一个群体,就容易有群体性的倾向。要么被同化,要么影响他人,要么责任感退化,甚至产生办公室政治。

社区的开发者来自不同地区、不同公司,多个公司的开发者相互协作,又彼此独立,大家在博弈中决定系统的需求和走向。和公司项目的区别在于,同一个公司里会有很多束缚,高层研发主管说句话,下面的人可能就遵从了。而互联网上,大家是通过摆事实、讲道理,而不是以身份、地位,或是服从个别公司的战略或产品计划来做决定。

Linux的发展和Windows不同,不会制定特别明确的目标。有人问Linus Torvalds,下个版本有什么功能,Linus的回答是:不知道!这是一种顺其自然的方式,新增功能完全取决于开发者想要写什么,只要代码经过了review、测试,达到了可以merge的质量就可以接收。Linux社区有不错的自由竞争机制,大家以独立贡献者的身份提交代码,淡化公司背景。重要的patch会被一轮又一轮的review,最后提交的版本往往跟初始版本大不一样。当然更糟糕的情况是直接被拒掉,或者有人提出别的竞争性方案。

这种模式也有不足之处,社区会经常性爆发Flame war口水战,很耗时间。相比Firefox、Apache等社区,Linux社区的Flame war是比较尖锐的。这种尖锐也被很多人欣赏,虽然拒掉patch很让人难堪,但的确对Linux长远发展有好处。

技术人攻略:Linux系统的复杂度越来越高,稳定性会不会越来越难以控制?

Kernel Summit上每年都会讨论这个问题,历史趋势就是这样的,任何系统都会越来越复杂。解决之道应该是更小心的开发和更强大的测试。

Linux发新版的速度很快,一般情况下两个月迭代一次,每天都有代码提交,每周都有一个RC版本。在Linux2.2、2.4的时候,一两年才出一个版本,代码之间互相影响的程度太大,系统搞得非常不稳定。所以现在提倡小步走,不要所有子系统都做大变动。Linux要发展,用户想要新feature,系统肯定会越来越大。能做到的就是对改代码的要求越来越高,越来越小心。明确要求代码要简单、容易理解、尺寸不能太大。我在做内核开发的时候,任何一点代码改动,都需要做各种场景的测试,这就导致写内核代码非常慢,每天能写10行就非常好了,不断锤炼之后,真正能merge进去就没多少了。

技术人攻略:你做Linux内核开发的成就感来自哪里?

Linux的使用范围很广,做内核开发,个人的智慧能最大限度被人用到,所以收获很大。当然也有代价,那就是进Upstream的难度很大,从能工作的代码,到Upstream能接受的标准,这中间要完成的工作,远比一般公司开发产品的标准要高。代码一旦进入社区,就意味着要由maintainer维护,所以对代码质量的要求不能放松,必须同时满足高效、通用、简单的特点。

我在社区的位置介于maintainer和sub-maintainer之间,维护比较小的tree,但可以直接给Linus Torvalds发请求。这两年精力主要花在这个测试工具上,现在仍然在不断完善它,比如加入了服务器的测试,将来会把手持设备系统加进来。Kernel Summit和Linus Torvalds都很重视测试,Linux内核要以质量、性能取胜,一定要有好的测试机制来保证。

对maintainer来说,越往里做,经验越丰富,做有趣的东西的机会就越少。review代码的工作量很大,而且更多是一种责任。因为他在这个领域最有经验,对这块的代码最了解,虽然眼界越来越宽,但做的具体事情越来越无趣。review别人的代码是个苦逼的事情,拒绝时不仅要给出足够理由,为了培养潜在的贡献者,还必须给他们引导,告诉他们怎么做比较好。每年Kernel Summit上,大家会针对这个问题吐槽,但暂时没有很好的解决办法。

技术人攻略:你第一次给社区提交patch的过程是怎样的?对于有志于从事内核开发的人,你有什么建议吗?

从第一次提交I/O预读patch,到接收为止,花了一年多时间。期间我一共写了十二个版本,从V1版本一直发到V5,社区才有人回应,一直到V12才被接收。当时提交到Andrew Mortan维护的mm tree,在接受之后,他又感觉我的算法太复杂,于是把我踢掉。Linux的核心原则是追求系统的简单性,所以我把主要功能保留,把出现的机会少,影响面比较小的功能去掉,这样才被最终接收。

这个过程中有两点很重要,第一是坚持,当别人不理你,或者是给你提很多意见的时候,你要很有毅力地不断满足他们,直到大家都认可。第二是提升自己,当我的patch没人理的时候,我就继续改进,包括看更多代码,对代码要吃得更透,做更多测试。还有就是在社区里观察和潜水,看邮件列表里面别人是怎么互动的。我当时重点看那些水平比较高的人,看他们怎么给别人的patch做review,他们会提很多关于如何改进代码的细致意见,我从邮件中学习到很多东西,也就知道自己该怎么做了。

想做内核开发,要动手,光读代码不可能深刻理解。一旦你开始写,会发现很多地方都理解错了,原来意识不到的问题都会暴露。初次写内核patch的人,行家一看就知道你是第一次写,会有很多细节上的问题。入门的人想写一个patch让内核接收,最好从bug fix入手,bug会以很高的优先级被maintainer处理,帮着你完善patch。初学者可以从这里了解整个流程,然后再去做重要的东西。Linux社区是基于信任的,如果一开始就动一些关键问题,却在格式上犯下低级错误,maintainer会不信任你。

做开源一个很大好处就是能快速提升能力,社区里面有各种背景的高手,patch有任何问题都会被挑出来。有时候我写patch,隐约感觉某个地方还做得不够好,但因为社区鼓励快速给原型,所以就发出去了,结果肯定有人指出其中的问题。社区会给你很多意想不到的东西,很快就能获得全方位的进步。

技术人攻略:Linux内核有哪些热点和变化?

变化年年都有,对于操作系统来说,硬件是地基。新的硬件趋势一出来,内核就要大改。上层应用有新的需求,内核也要适应。

多核给CPU带来巨大挑战,每个CPU都有自己的内存,访问不同内存的速度不同,这个过程要去优化。NUMA调度,非一致性内存架构,都是当前热点。另一大热点是power-aware scheduling。如果系统只有一个进程在忙,其他核是不是能关掉?如果有几个进程在忙,能不能到一个核上去跑,让它节能,或者让它分散,获得更高的性能?CPU越来越复杂,操作系统需要有调频策略,什么时候升频,什么时候降频,CPU某些部分的电源是否可以关掉,这些都需要不断改进。内核系统里现在有越来越多难缠的问题,用户究竟想要性能还是节能,并没有明确的结论,只能在权衡中前进。

存储方面的变化,先看内存。内存特点是越来越大,原来系统内存是4G,以4k页面的单位进行管理,相当于维护10的6次方个项目。但如果内存量级暴涨,4T变成常态,那就有必要增大内存管理的粒度。内存页面是非常基本的数据结构,从4k变成64k,不是简单的量级变化。CPU页的单位就是4k,一旦硬件和内核的单位不是原子性对应,数据一致性问题就难以保证。

SSD也给存储带来了变化,内核假设磁盘是一个慢设备,现在快了好几个量级,原来那些代码开销就大了。多队列处理也是热点,I/O量已经比一个CPU快,需要分到多个CPU。随之而来的问题是,不同CPU处理这些中断,对应的数据结构不能有耦合。多个CPU需要加锁,而一旦加锁,速度就慢下来了。

当前热门的云计算领域,也对内核提出了挑战。KVM的I/O scalability还有待改进。目前CPU、内存、网络、I/O等方面的cgroup隔离都可用了,只是I/O cgroup实现在块设备层,对NFS等情况不适用,此外因为I/O回写要通过缓存,还实现不了真正的隔离。

技术人攻略:作为一个内核高手,你的生活和社交圈子是怎样的?

社交圈主要集中在网络上这帮Linux社区的朋友。在生活中,我就算一个人关在屋里也不会觉得闷,但如果让我去跟其他技术人社交,我也不排斥。一般这种聚会我不会主动去,但去了也会挺享受的。至于工作,我签的合同是远程办公,公司允许这种比较自由的工作方式。我曾在广西巴马的长寿村住过一阵,紧张的工作之后,一出房间就可以很放松,不像城市里那种忙忙碌碌。那段时间每天爬山,整个人都神清气爽,工作效率也高。很喜欢这种生活,其实我的梦想就是住在山里面,听听鸟叫,冥想,享受生活。


技术人攻略访谈是关于技术人生活和成长的系列访问,由独立媒体人Gracia创立和维护。报道内容以“人”为核心,通过技术人的故事传递技术梦想;同时以小见大,见证技术的发展和行业的变迁。在这个前所未有的变革时代下,我们的眼光将投向有关:创造力、好奇心、冒险精神,这样一些长期被忽略的美好品质上。相信通过这样一群心怀梦想,并且正脚踏实地在改变世界的技术人,这些美好的东西将重新获得珍视。

联系方式 gracia@devlevelup.com
微博: @技术人攻略
订阅:微信搜“技术人攻略”或“dev-levelup”
请输入图片描述

感谢SegmentFault提供博客专栏及推广支持。
感谢迅达云成提供云主机及技术支持。

阅读 16.3k

推荐阅读
技术人攻略
用户专栏

关注技术人的个人成长,讲述技术人自己的故事,传递技术梦想。

69 人关注
56 篇文章
专栏主页