开源社KAIYUANSHE

以下文章来源于ALC Beijing ,作者姜逸坤

| 作者:姜逸坤

| 编辑:梅嘉宜

| 责编:钱睿

| 设计:杨敏

2022年6月16日,Apache Spark 3.3版本正式发布,包含了支持K8S自定义调度的功能,让Spark on K8S能够支持Job粒度的调度。

我也作为主要发起人经历了这个方案落入的全过程,从需求搜集,到跨多个社区达成共识,并在有限的时间窗内完成代码的合入,一路充满挑战,也让我快速成长。该方案也作为Spark 3.3重点特性发布。

而这篇文章则记录了在整个过程中,我们遇到的困难,挑战以及我们在解决这些问题的收获与思考。

无人问津:哪里出了问题?

风会熄灭蜡烛,却能使火越烧越旺。对随机性、不确定性和混沌也是一样:你要利用它们,而不是躲避它们。你要成为火,渴望得到风对吹拂。

——《反脆弱:从不确定性中获益》

2021年11月1日,我怀着忐忑的心情在Spark社区提交了第一版代码的实现 https://github.com/apache/spa...,500行代码,10个文件,侵入性修改,臃肿的SDK,简单的几个UT。依稀记着那时的心情,混杂着方案基本形成的欣喜,担心实现被反对的不安,希望得到代码review的期待。

然而,现实比想象更加残酷,1天过去了,没有comments,2天过去了,还是没有comments,1周过去了,这个PR孤零零地躺在哪里,无人问津。

当我们在社区遇到这种情况,不妨我们现在Reviewer的角度,来看看这个问题:

1. 你的方案足够通用吗?方案不够通用,虽然只是一个POC的实现,但整体方案并不通用,夹杂着侵入式的修改,数据结构未解耦等多个问题。同时,如何灵活、动态的加载,以实现对不同调度器的支持也是一个关键。

2. 你的方案社区了解和信任吗?方案本身是一个比较大的改动,参与社区review的开发者,并未端到端的理解我们的方案解决是什么问题、有什么好处、有什么风险。

3. 你的方案提出时机合理吗?时间上,Spark 3.2版本正在关键的release阶段,社区的带宽都集中在版本发布上,我们需要一个更合适的时间来让社区充分的review。

除此之外,建立社区的信任感也是一个长期的过程,我们需要积极参与社区的所有贡献。就像新员工刚进公司会从简单的事情做起一样,从一点一滴做起,在某个领域积累足够的信任,这样社区也会对你的方案更加有好感。

在开源社区中,我经常会因为各种原因导致代码无法合入,我们要直面问题,换位思考,从现象看本质,把不确定变为尽可能的确定。

发起讨论:让社区了解我们的意图

暴风雨!暴风雨就要来啦!这是勇敢的海燕,在怒吼的大海上,在闪电中间,高傲地飞翔;这是胜利的预言家在叫喊:让暴风雨来得更猛烈些吧!——《海燕》

2021年11月30日,我点下send键的那一刻,我知道,这封讨论邮件将抵达世界上成千上万的Spark社区开发者的邮箱里。这一次,相比前一次那个无人问津的PR来说,我的心情少了一丝忐忑,但是我也清楚接踵而来的可能是更广泛的反馈和更激烈的讨论。

在Spark社区,通过Spark project improvement proposals (SPIP)来帮助社区的开发者完成proposal,下面是来自Spark 官方对SPIP的说明:

而SPIP主要分为讨论、投票、投票发布等几个关键环节。在社区邮件列表发起讨论后,就会有很多与你有共同目标的人参与讨论,社区的开发者们也会在这个过程中反馈自己的需求,帮助你共同改进。当社区所有人的问题都被解决,达成共识后,也便形成了最终的方案。

刚参与开源社区的同学们,有时会有些惧怕在社区交流,尤其是国内的开发者,因为语言的不同会变得不自信。最开始在社区开发时,我经常会说,“我英语不太好,希望你不要介意”,而其中一个Committer说,“你的英语肯定比我的中文好,哈哈”。如果实在不放心还可以使用机器翻译软件。

所以,只要我们表达出核心的意思,把问题说清楚就好,同时,在写技术文档和方案时,也可以参考同领域内其他历史的文档去学习,读得多了也自然就会写了。

开源社区中的开发:"从0到1"与"从1到N"

从POC的无人问津到正式方案的广泛讨论,让我深刻地认识到,我们不但应该关注从0到1的添加一个调度组件的支持,更需要考虑从1到N的演进。尤其在开源社区中,更应该关注通用性以及未来的演进。

之前已经提到过,对于我们的这个方案,技术上最大的难点在于:兼顾种类繁多的自定义调度集成的通用性,开发者集成以及最终用户使用的易用性。因此,我们在正式方案的设计阶段,我们做了2个比较大的重构:

- 通用性。通过引入支持配置通用的动态加载机制,来满足各个调度器的切换,同时新增通用的API接口,来满足各种调度器所支持的不同接口。

- 解耦。将第三方调度器所依赖的CRD解耦。例如,Volcano的PodGroup,迁移至kubernetes-client,确保数据结构的解耦,这样Spark只需要升级kubernetes-client即可完成Volcano的支持。

Comunity over the code:促成共识,我们

要做些什么?

汝果欲学诗,功夫在诗外

2021年12月,我们花了几乎整整一个月的时间,来解答社区的疑问,处理了近百条的评论和建议。那段时间真的是无时无刻不在看社区的评论,半夜起来上厕所都想看看有没有新的回复。

有很多刚参与开源社区的同学,会误认为代码高于一切(或许是Talk is cheap show me the code的误导?哈哈),从而忽略社区的本质。其实就和联合国去征集提案的建议一样,当一个提案提出时,各个国家都会进行投票,然后投票通过则提案通过,即使一个国家再强势,最终结果也会顺从民意。开源社区的投票也是如此,需要兼顾大多数人的利益。

当然,一个开放治理的开源社区,有争议的决策并不是某个人或者某个厂商去决定的,而是社区的用户、开发者们,最终投票达成共识。这也是为什么一般的开源社区都会提供非常多交流渠道(比如Slack、Mailing list、Meetup)的意义。我们利用这些渠道,做了以下几件事:

1. 与社区关心这个SPIP的定期线上交流。我们通过线上和线下的会议,和一起合作的作者、牧羊人、Reviewer讨论我们的风险、计划和进展。

3. 和最终的社区用户实时同步方案的变化。有时候和POC的代码已经完全不一致了,尤其是一些细节的改变,会在用户、开发者的接口上有很大的差异。例如,在我们推进的过程中,和华为、字节、网易、Netflix、Cloudera等很多最终的用户实时同步进展,确保方案的通用性。

这个SPIP中,来自Cloudera、Netflix、Nvidia、Apple、AWS的开发者都给出了非常多有价值的建议,也让我们这个SPIP变得更加通用,经过整个社区的review,也会让社区变得更加有信心。最终,2022年1月,投票通过。

来自PMC的警告:不要高兴得太早

在SPIP投票通过后,当我们开始提交PR后,Apple的Spark PMC发了一个善意的警醒

大意是:请注意Spark有一段悲惨的历史:之前有个Graph的模块,通过了SPIP的投票,我也帮助合入了依赖并且新增了Graph模块,但是由于review出现分歧以及牧羊人的退出,最终导致Spark Graph没有进入Spark项目,最后导致这个依赖被回退。

这个问题包含了2个关键信息:

2. 尽早将可能的问题暴露。尽早地将方案给出,从而避免后期出现分歧拖延项目进度。

有兴趣的可以看看这里:

https://github.com/apache/spa...

Lesson learned:危机的化解与跨社区合作的启示

突然出现的危机,大多数的情况是因为多个小问题同时出现,而产生的雪崩效应,再伴随着主观的情绪因素被放大,最终形成看似无法化解的危机。而我们需要做的是首先将危机分解为小问题,把已有的小问题挨个解决,并且设计一种合理的机制防止危机再次出现。

为了快速验证,我们开始是采用了dev分支进行跨社区联调,并且最初是打算在Code Freeze后,将Volcano Version固定到静态的tag。而在Spark Code Freeze的前3天,当时由于Volcano修复了一个问题(非法参数的验证功能),导致了我们之前Spark的部分设计不合理的用例失败了。这时,引发了社区的关注和质疑。

而开源社区最大的一个特点就是“open”,其中一个含义就是透明 。当我们遇到问题时,做的就是直面对方的质疑,毫无保留地暴露出原有的问题,事无巨细地解释解决问题的过程。

什么是Volcano版本控制的机制?Volcano机制没有问题,latest分支是开发分支,是我决策的失误(之前选择开发分支是为了能够快速验证,而忽略了稳定性),我们应该使用固定版本的tag分支。

为什么latest分支会出现这个问题?根本原因是因为K8s新版本发布,有breaking的变化,Volcano在最近才做了适配。适配前,参数校验(webhook)的功能失效了,现在修复后,导致我们之前设计不合理的用例才暴露出来。

和Spark配合的Volcano版本应该是什么? 我们最终会选择一个固定的版本而不是开发分支。

这也给我们了一个启示,就是在跨社区合作的过程中,我们要尽早确定版本的依赖,而不应该使用dev分支。

感兴趣的可以看看这个comments:https://github.com/apache/spa...

社区的力量:你在帮助社区的同时,社区也在帮你

在整个SPIP推进的过程中,不光是我一个人在战斗,例如:

- 来自Apple的Spark PMC,在代码落地阶段,给出了非常多关键性的review,帮助我们完成代码的落地以及对整体项目进展的把握。

- 来自Netflix的Spark PMC作为牧羊人,在SPIP的推进过程中以及关键代码的合入给了很多的建议。

- 来自Volcano社区的Committer们积极响应和配合,是他们的努力和帮助,让Volcano作为这个方案的第一个参考实现变成现实。

- 来自Yunikorn社区的Maintainer在设计的review中,使得整个方案变得更加通用。

- 来自Cloudera的Spark Committer,在插件化的接口设计中,给出了关键的建议。

- 来自Databricks的Spark PMC在社区SPIP推进的早期阶段,给了我们非常多建议。

- 来自网易的Spark Committer,在模板化配置的关键机制中提供了很多经验性的建议。

- 来自字节的负责Spark基础设施的同学,给出了非常多从用户角度的输入。

……

没有他们的帮助,这个SPIP不会成功。而开源社区的每一天、每一夜,也一样,你不会孤立无援,都有来自世界各地的杰出开发者们和你们一起战斗!

相关阅读 | Related Reading

COSCon'22主论坛来袭 开源站在十字路口

技术播客月 | 开发者社区运营是怎么样一个体验?

我所理解的开源软件供应链安全

开源社简介

开源社成立于 2014 年,是由志愿贡献于开源事业的个人成员,依 “贡献、共识、共治” 原则所组成,始终维持厂商中立、公益、非营利的特点,是最早以 “开源治理、国际接轨、社区发展、开源项目” 为使命的开源社区联合体。开源社积极与支持开源的社区、企业以及政府相关单位紧密合作,以 “立足中国、贡献全球” 为愿景,旨在共创健康可持续发展的开源生态,推动中国开源社区成为全球开源体系的积极参与及贡献者。

2017 年,开源社转型为完全由个人成员组成,参照 ASF 等国际顶级开源基金会的治理模式运作。近八年来,链接了数万名开源人,集聚了上千名社区成员及志愿者、海内外数百位讲师,合作了近百家赞助、媒体、社区伙伴。


开源社
11 声望2 粉丝

开源社成立于 2014 年,是由志愿贡献于开源事业的个人成员,依 “贡献、共识、共治” 原则所组成,始终维持厂商中立、公益、非营利的特点,是最早以 “开源治理、国际接轨、社区发展、开源项目” 为使命的开源社区联...