GSOC 2023 - 我的第一次开源之旅

写在前面

今天北京时间凌晨 2 点左右,Google 给我发邮件确认了项目终审通过,3 个多月以来的 GSOC(Google Summer of Code) 活动算是圆满结束了。今年 5 月份以来我在 GSOC 、 OSPP(Open Source Promotion Plan 中科院办的开源之夏) 和实验室的完蛋项目里三线作战来回捣腾焦头烂额 😶,这也是我博客一直没有更新的原因。三大战役之一终于收官了,这才忍不住来更新一下博客,只是想告诉大家我没有太监(:

这页博客主要内容其实是我想说说这次 GSOC —— 也是我第一次参加开源项目 —— 的感受,想看我的 GSOC 项目的具体内容可以参考这个链接,想要参考我项目提案(Proposal)的可以看这里,想直接看我做了啥东西出来的可以直接看这个文档,不想看我下面逼逼赖赖的可以输入组合技 CTRL + W

gsoc-completion-certificate.png

在这之前

最开始了解开源,其实是在 2022 年末,看到实验室看到学长参加 OSPP 拿了个优秀学员(他的博客 👉 https://siegelion.cn/ ,技术力真的很强),然后想着 wow, cooooooollllll! 给数万用户用的开源项目里留下自己的代码真的太拉风了。要是出去工作,突然有一天同事问你:诶,这个库的这个代码 author 怎么是你?我:🕶

那么时间最近的开源活动其实就是 GSOC(Google Summer of Code) 了,实际上 GSOC 是最早的学生开源活动,是国内 OSPP, GLCC 的祖师爷,而且谷歌的背书也是全球通用的。不过相应的,GSOC 的申请难度不低,并且最大的问题就在于沟通 —— 你很大概率会碰上完全不会中文,甚至是非英语母语的 Mentor(项目导师)。而沟通恰恰是完成一个开源项目的关键,没有沟通别说技术指导、项目规划、社区要求了,甚至连 ddl 都没法准确的通知你。所以其实网络上很多人建议国内的开源新手先通过 OSPP、GLCC 这些活动上手,除非你的英语能力高强、或是能够找到国人 Mentor 指导的项目。

我在一开始申请的时候就是由于上述的原因,其实是抱着试试的心态申请的,做好了颗粒无收的准备。既然死猪不怕开水烫,那我想我直接去找那些最有名的 Org 的项目报吧。我大概浏览了一遍,GSOC 的组织机构中,国人社区比较多的都集中在 Apache 和 CNCF 这俩里头。但是国人社区国人导师的项目,不用想竞争肯定非常激烈,并且绝大多数项目单单那高大上的名字和眼花缭乱的技术栈就让我望而却步。根据我自己的技术栈积累和一次超短期实习经历(这篇博客的来由),我找到了 Apache SkyWalking 社区的 Python Agent Performance Enhancement Plan 这个项目。Apache SkyWalking吴晟老师创建的开源社区,而这个项目不仅适合我的技术能力,它的 Mentor 还是美国东部时区的,这样我的竞争对手就会少了一些(无论是来自国内还是国外的)。我费劲心思,集百度谷歌 deepl 各家翻译之所长,洋洋洒洒地写了一封全英文邮件给这位 Mentor,结果第二天一看回信我就傻眼了:

都是中国人,咱们讲中国话。

我都做了些什么

实际上,我的邮件是 2 月份发出去的,就是在 GSOC 组委会正在确定项目组织机构的时候。这个时间段其实比正常的申请时间要早一点,我觉得这也是我能侥幸中选的原因之一,因为我早早把坑给占好了。实际上后来还有个印度哥们也想来报这个项目,但是那个时候我已经开始在社区里做项目准备工作了。

Proposal 我也构思了不少时间,参考了 github 上一些往届学生的例子,当然最后会交给 Mentor 润色,不过 95%都是要靠自己完成的,看这里。Proposal 主要还是要表达出对项目的理解、希望采用的技术方案并最好有实践例子、项目的时间安排等,篇幅完全不是最重要的。之所以专门提了一下 Proposal 的重要性,是因为后来我的 Mentor 告诉我 SkyWalking 社区 10 个项目最后只有 6 个被选上,其它的都被 Google 毙掉了,即使贡献者已经和 Mentor 商量好了(这种情况在 OSPP 基本不会发生)。

其实我第一个给开源社区贡献的代码,并不是这个项目的代码。而是在社区混脸熟的时候找到了一个 bug ,顺手给修复了(PR 见此)。这个 PR 实际上给了我很多好处,第一个就是让我的 Mentor 觉得“孺子可教也”,然后也能让社区里的其它人,比如吴晟老师,对我的名字也有了印象,毕竟后面他们 review 我的项目代码的时候还指望他们手下留情 😂。不过这个 PR 最重要的,还是帮助我成功申请到了我 OSPP 的项目,这个是后话了,希望一两个月后还能贴个博客谈谈。

关于时间安排方面,上面的完成证明说的是 5 月末开始,实际上我 4 月份就正式开始做项目内容了,大约 6 月中旬的时候我已经基本完成了所有的功能点,我和 Mentor 之间的合作主要就集中在这个时间段。不得不说,我没有这么尽心尽责的 Mentor ,我的项目不会完成的这么顺利。技术层面上,我做的工作可以通过我的这个技术文档来做总结,这里来罗列一下我遇到的主要的难点和解决方案吧:

首先是AsyncIO 协程的跨线程调用。Python asyncio 实际上是基于 eventloop 这一模型实现的单线程异步库。也就是说运行 eventloop 的线程必然不可能是 SkyWalking Python agent 的主线程,否则用户甚至都无法访问 agent 的 API。然而,用户的监控数据仍然需要通过 API 传递到 agent 核心队列中再依次上报给 SkyWalking 后端。在原先的 Python 线程模型中,由于 Python 的队列是线程安全的,因此只需要调用队列的 get()/put() 即可。而现在,则需要数据流向从 主线程->队列->处理线程->上报线程 变更到 主线程->队列-> eventloop 线程->处理协程->上报协程

为此,我将全局通用的队列更改为 eventloop 线程专用的 asyncio.Queue,而在主线程和 eventloop 线程之间的队列生产/消费,则直接采用run_coroutine_threadsafe() 方法将协程任务投递到 eventloop 线程中。这样就能够保证数据的安全性,同时也不会阻塞主线程。这里我和 Mentor 其实讨论了很久,因为这个方案的实现并不是很优雅,跨线程调用协程似乎有悖于Performance Enhancement这一主题。我们还考虑过使用协程与线程同时安全的队列 janus 等,但是最终还是采用了这个方案,因为这个方案的实现成本最低,而且也不会影响到用户的使用。

然后就是监测 Python agent 的性能瓶颈。这一块就是完完全全的让我学到新东西了,Mentor 先让我了解通过 yappi 解析 Python 程序的性能瓶颈,然后再通过 WRK 等测试工具对接口进行压力测试,这里真的非常感谢 Mentor 的指导。我的性能优化 30% 的结论一部分就是根据这里得出来的,当然其实在这之中我们还发现了一个新问题:除了 IO 耗时,agent 内部的 UUID 生成器也是耗时的主要瓶颈。由于它不是我的项目内部的需求,这里就只让 Mentor 记录下来了,如果看到这的你想要抓住机会贡献代码,那就是现在 😀。

接下来?

GSOC 2023 算是告一段落了,但我开源的脚步已经迈开并且不会停下。最近开题、实验室项目和 OSPP 已经让我分身乏术了,GSOC 的这个好消息算是给我来了针强心剂。希望一两个月后的 OSPP 结项能再写个杂谈出来吧 💪。