LWN:Google 更加靠近 mainline 开发!

Linux News搬运工

共 7657字,需浏览 16分钟

 ·

2021-10-24 14:03

关注了就能看到更多这么棒的文章哦~

Moving Google toward the mainline

By Jake Edge
October 5, 2021
OSSNA
DeepL assisted translation
https://lwn.net/Articles/871195/

两位谷歌工程师来到 2021 年北美开源峰会介绍了一个项目,该项目旨在改变该公司在其数据中心的生产系统上运行的 kernel 的创建和维护方式。Andrew Delgadillo 和 Dylan Hatch 介绍了目前的生产内核(Prodkernel)以及由于它与 mainline 差异很大而出现的一些问题。Project Icebreaker 就是为了能进行改变,为谷歌内部的开发和测试提供一个接近 mainline 的内核。该讲座探讨了该项目、它的风险、它的当前状态和后续计划。

Prodkernel

Delgadillo 从 Prodkernel 开始介绍,Prodkernel 是谷歌数据中心的大多数机器上运行的内核。这些系统的用途包括处理搜索请求以及 "其他对外和对内的工作",他说。Prodkernel 是基于一个旧版本的 upstream Linux kernel,添加了 9000 个 patch。这些 patch 实现了各种内部 API(例如谷歌光纤 Google Fibers),提供了硬件支持,进行了性能优化,并包含其他一些 "运行我们在谷歌使用的二进制文件需要的调整"。每隔两年左右,这些 patch 就会被 rebase 到一个更新一些的内核版本上,这就带来了一些挑战。首先,内核在两年内有了很多变化,哪怕某个功能的 rebase 看起来很正常,但是如果碰到了 bug 的话,去分析是哪里出现的问题,都会经历一个 "非常大的搜索空间"。

[Andrew Delgadillo]

他说,有一些特定的内部需求以及 schedule 决定了对 Prodkernel 的需求,这就是为什么谷歌不能直接使用 mainline 并将所有需要的额外功能都合入 mainline。他举了一些例子,其中提到的谷歌生产环境使用场景所需要的功能,但这些功能在 mainline 中是不存在的。其中包括需要能够从 user space 来给出站网络流量(outgoing network traffic)设置 qos、为 out-of-memory(OOM)killer 配置一些具体规则,并为用户空间的 cooperative scheduling 增加新的 API。

他说,Prodkernel 存在的一个大问题是它减弱了对 upstream 的参与度。谷歌为生产环境开发的任何功能都是在 Prodkernel 上开发和测试的,而它可能比主线内核落后两年。如果开发者想为 mainline 功能提出一个新功能的话,使用 Prodkernel 的模式会带来两个主要问题。其一,这个新功能需要 rebase 到 mainline,当版本之间的差异很大时,这个任务本身可能就很困难了。即使能完成这一步,那么还有一个问题,也就是如何测试该功能。该功能已经在 Prodkernel 的生产环境使用场景中得到了验证,但是现在它已经被拿到了一个新的环境中,与很不一样的源代码组合在一起。这个新的组合无法不能在生产环境中测试,因为 mainline 缺乏 Prodkernel 的其他功能。

谷歌的工作场景倾向于尽量把性能瓶颈、死锁和其他类型的错误都检测出来,但使用 Prodkernel 就意味着这些检测机制对其他人无法提供帮助。例如,如果谷歌运行的是接近 LTS stable kernel,那么报告这个 bug 就可能会使团队找到一个可以 backport 回去的 fix。但现在一般来说发现和 fix 这些 bug 都只能是谷歌自己做的事情了。此外,任何 fix 都可能对其他人没有丝毫用处,因为它们是针对一个多年前版本的内核的。另外,所有在最近的 kernel 中被 fix 的错误都不会被发现,直到人们真的发现有这么个 fix,才会进行 backport,或者就得等到下一次的 rebase 完成了。

rebase 过程是 "非常费时费力的",它占用了开发人员可以用来做其他事情的时间。每一个 patch 都必须解决与 upstream kernel 的冲突;很可能开发者在开发代码之后已经过了一年或更长时间都没有再碰过过这段代码了,但他们必须重新回忆当时的情况、完成 rebase。当然,这样做完之后产生的内核必须用谷歌的使用场景来重新验证。在这个过程中发现的错误可能就很难找出 root cause 了。当然我们可以对 kernel 改动进行 bisect 来查找引入问题的改动,但是在每一步中都需要解决 rebase 引发的合并冲突。这个过程也许可以自动化,但它仍然是一个很困难的工作流程,他说。

与 rebase 工作相关的这个 delay,使得 upstream 的参与度问题变得更加恶化了,这使得下一次 rebase 就需要更多的时间。很明显,这就是 technical debt 的一个实例,Delgadillo 认为,而且这个 debt 还在不断增长。每一次 rebase Prodkernel 的时候都会增加 patch 数量,这就导致下一次 rebase 的时间会更长。这种做法是不可能持续的。所以需要努力减少 technical debt,从而能腾出时间来提高 upstream 参与度,进而进一步减少 technical debt。

Icebreaker

[Dylan-Hatch]

Hatch 随后介绍了 Project Icebreaker,这是谷歌在进行的一个新的 kernel project,它有两个主要目标。第一个目标是紧跟 upstream kernel。我们的想法是为每一个主要的 upstream kernel 版本都发布一个新的 icebreaker kernel。新版本的发布需要是 "on time,我们需要保持与 upstream Linux 的同步"。这将为开发者提供一个添加新 feature 的平台,这个平台与 mainline 足够接近,然后这些功能就可以直接向 upstream 提出了。

第二个目标是能够在该内核上运行谷歌二进制文件。这将是一个 "真正的生产内核",可以在 Prodkernel rebase 之前就完成 upstream 改动的验证。他说,在目前的计划中,谷歌一直是 "把所有东西都在两年前的版本之上"。有了 Icebreaker,这个测试工作基本上都可以在每次发布新的 mainline kernel 后马上就开始。

这些目标很重要,因为该团队需要 "更好地参与 upstream"。开发人员在为远离当前 mainline 的内核开发新功能时,很难看到让该功能进入 upstream 有什么好处。他需要做大量的工作来将这个新功能从 Prodkernel 中分离出来、在 mainline 内核上进行测试、然后再向上游提出建议。做了这么多事情之后,还仍然无法确定这个功能是否会被 upstream 所接受。另一种做法就是直接等待 rebase,专门分配时间来做 rebase 工作,但是一旦新的 Prodkernel 验证完整之后,也就再次没有动力去把这个 feature 推动到 upstream 去了。

让 kernel 更接近 mainline 也会帮助谷歌更快地验证所有的上游补丁。与其等到两年后再做费劲的 rebase 和重新测试的工作,不如将这些工作摊薄在更长的一段时间内。

Structure

他说,在看待 Icebreaker 这个工作的 structure 时,有两个方面需要考虑。一方面是如何开发功能,以使它们能部署在 icebreaker kernel 上。另一方面是在有新的 mainline kernel 之后,如何将这些 patch 升级到下一个 icebreaker 版本上去。

Icebreaker 会从 mainline kernel fork 出来。它会添加一堆 feature branch(也被称为 "topic branch"),每一个这样的 branch 都是针对谷歌正在添加的这个功能的一组独立的 patch set。这个方式本身就很有用,因为每一个这样的 branch,其中的 patch 都是一组可以推到 upstream 的 patch series。"所以你的起始点就是一些可以推到 upstream 的内容,而不是混杂在一起",Hatch 说。

开发工作会在这些 feature branch 上进行,然后根据需要来添加 bug fix 和新 feature。最终,这些 feature branch 会先被 merge 到相关子系统的 staging branch 中进行测试。然后再把 staging branch 合并到另一个 branch 来进行发布。他说,这个最终 branch 就是一个 icebreaker kernel,它已经 "可以使用了,而且它的根源仍然是那些 feature branch"。在发布之后,会进行一次 "fan-out merge 来把改动合并到 staging branch",从而使这些 staging branch 的内容也跟上了发布版本。重要的是,这种 fan-out merge 操作并不会对 feature branch 进行。那些 branch 仍然保持着原始的可以 upstream 的状态。

他说,通过跟踪这些 feature branch 的生命周期,我们就可以看到这个升级过程是如何进行的。当一个新的 mainline kernel 发布时,就会创建一个新的 feature branch,并将早期内核的 branch 合并到该 branch 之上。早期的 feature branch 上的提交的 SHA1 值被保留记录下来,而解决合并冲突的代码也可以在 merge commit 中看到。

在这种工作流程中,错误处理就更加容易了。bug 可以在仍在支持的最早的 feature branch 上进行 fix,然后再合并到所有后续的 feature branch 上。引入 bug 的 commit 以及和 fix commit 的 SHA1 在其他分支上保持一致。就不再需要来使用其他的 metadata 来跟踪不同的内核版本中的相应 fix patch 了。

Hatch 说,Icebreaker model 比目前的 Prodkernel 方案来说更有利于推动代码到 upstream。Icebreaker 的 feature branch 是在最新的 mainline kernel 上完成的,它们就以这种方式进行测试,所以测试结果与 upstream 更加吻合。这将使开发人员更容易为 mainline 提出新功能 patch。演讲的幻灯片中可以看到更多的 Icebreaker branch 相关信息。

Risks

他说:"不幸的是,Icebreaker 还是有一些风险"。其中一个较大的风险是,需要有大量的 feature branch 用来测试。人们可能会倾向于把这些 branch 当作一个文件柜,把 patch 都储存在这里,然后 merge 到需要的地方。但是,如果不能确定这个 branch "是否可以完成 build 或 boot,以及能通过所有测试",那这就没有用了。

因此,在将其 merge 到其他 branch 之前,需要对该 feature branch 进行验证。如果能确认它在 merge 出去之前是能正常工作的,那么随后的任何 bug 都应该是由 merge 过程中的某些改动造成的。否则如果把一个未知状态的 feature 合并到一个新的 branch 上,只会让情况变得复杂。他说,每次升级到一个新的 mainline kernel 版本时也是如此。

feature 之间的依赖性也可能是 icebreaker 的一个风险。设计流程的时候假设这些 feature 大多是互相独立的,但这并不完全正确。它们之间会有一些相互依赖性。比如某个 feature 提供了在另一个 feature 中要使用的 API、或者一个 feature 正确完成其工作所需的性能优化。这可以通过在 staging branch 之上解决依赖关系来处理,但这些 staging branch 不会被带到下一个 icebreaker kernel,只有 feature branch 才会用到。

所以解决方案就是在 feature branch 之间进行 merge,这确实可行,但也增加了一些复杂性。有必要弄清楚哪些 branch 是可以相互 merge 的。他提出了一个问题:"我们可以让这些 merge 变得多么疯狂?"。没有规则规定什么时候两个 feature branch 应该简单地合并成为一个 feature branch,或者哪些情况下确保它们是独立的。这些都必须根据具体情况来决定。

另一个风险是 Icebreaker 没有 Prodkernel 的工作流程那么集中。谷歌内部 feature 的负责人和子系统维护者都需要参与并接受这个新的工作流程和工作模式。他们需要相信这个新的 icebreaker 计划(早期阶段肯定是混乱和复杂的)实际上会给大家带来更好的结果,并且减少 technical debt。

Hatch 所提出的最后一个风险是,Icebreaker 的 feature 还是必须要推到 upstream 的,否则它将再次演变为又一个 Prodkernel。如果越来越多的 patch 被添加到 Icebreaker,但又没有因为一些 feature 进入到 upstream 而减少一些 patch,那么大家仍然将无法跟上 mainline。production kernel 团队需要利用 Icebreaker 非常接近 mainline 的这个优势,来让将这些 feature 尽量合入 mainline。

Status and plans

Delgadillo 接下来谈论了 icebreaker 的当前状态。在此时此刻,它是基于 5.13 内核的了,而此时 5.15 内核正处于 release candidate 阶段。因此,该项目基本上比 mainline 晚了一个主版本,这是 "比我们以往的程度要接近得多了"。

[Dylan Hatch & Andrew Delgadillo]。

在这个过程中,大约有 30 个 patch 已经不再维护在内部 branch 上了,因为它们已经被 merge 到 upstream 了。他说,在 9000 个补丁中,30 个听起来可能不算很多,但这是一个开始。如果没有像 icebreaker 这样的项目,这是不可能发生的事情。该团队现在正在开发 5.14 版本,完成之后就能够抛弃 12 个 feature branch 了,它们都是谷歌从 mainline 移植过来的功能,但对于最近版本 kernel 来说就不再需要了。他说,这是对 technical debt 的另一个削减。希望这个过程后续能变得 "越来越容易,因为我们在不断前进"。

此外,这个过程中也发现了一些 bug,进行了 fix,然后报告给了 upstream,或者正在往 stable tree 进行 backport。在使用 Prodkernel 的时候,这种情况很少发生,因为它远远落后于 mainline。目前看到的这些 fix 主要还是编译错误之类的 fix,但还是对其他人有用的,这已经是现在方式的优点了。

展望未来,Icebreaker 计划在 5.15 或 5.16 的时候追赶上 upstream,这将是此项目的一个转折点。他说,到那时,它将可以完全利用 upstream 的进展,这就可以允许 "我们放慢对自己代码 tree 进行 upgrade 的节奏了"。目前出现的一个问题是,在 Icebreaker 努力追赶的过程中,feature 维护者不得不每隔三四个星期就重新进行 rebase 以及 fix 合并冲突,而在 Prodkernel 模式中,这个工作只会每两年左右进行一次。一旦项目追赶上最新版本 kernel,那么就会只需要每 10 周左右进行一次 rebase,这就与 mainline 的时间表保持一致了。

在 mainline kernel 的 release candidate 版本的基础上来对 icebreaker 的 feature branch 进行测试,这也是 icebreaker 项目希望能做的事情。这就会让谷歌也参与到 release candidate 的流程中,帮助测试这些 kernel。等 Icebreaker 与 mainline 完全对齐之后,完全可以针对 upstream 代码进行 feature 开发了,而这是 Prodkernel 无法做到的。

接下来,Delgadillo 和 Hatch 接受了大家的提问。第一个问题是关于 Prodkernel 的后续计划:是否仍然会有巨大的、为期两年的 rebase?哈奇说,目前 icebreaker 和 Prodkernel 在并行进行。Delgadillo 指出,icebreaker 这个新东西不一定能解决所有的问题。他还说,虽然 Icebreaker 在功能上与 Prodkernel 相当,但它在性能上可能并不相等。在生产环境中运行这些 kernel 绝对是他们的目标,但这一步目前还没有真正达到。

读者可以将这个演讲与 2009 年内核峰会上的一个演讲 (https://lwn.net/Articles/357658/) 进行一下对比,应该会是是很有趣的,那篇文章对 12 年前的情况进行了介绍。

[编者感谢 LWN 的订阅者支持我去西雅图参加北美开源峰会。]

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~



浏览 37
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报