摘要:团队用 7 个月写了 27 万行 C++ 代码,为什么突然要 用 Rust 重写,来 看数据库创业公司 RisingWave L abs 创始人兼首席执行官吴英骏博士的现身说法。
链接:https://medium.com/@Aaron0928/the-founder-of-the-database-rewrite-with-rust-is-back-was-it-worth-deleting-270-000-lines-of-c-46a8713bd8e6
声明:本文为 CSDN 翻译,未经允许禁止转载。
(资料图片)
作者 | Aaron 0928
译者 | 弯月 责编 | 郑丽媛
出品 | CSDN(ID:CSDNnews)
前段时间,数据库创业公司 RisingWave Labs 发表博文,宣布彻底删除RisingWave(该公司的云原生流数据库)的 27 万行 C++ 代码,并用 Rust 语言重写。
为此,我们采访了该公司的创始人兼首席执行官吴英骏博士,详细探讨了重写的前中后期准备工作、遇到的问题以及经验教训。
提问:选择哪种编程语言与 RisingWave 的功能有关系吗?
吴英骏: RisingWave 是一款云原生流式数据库,主要服务于需要超低延迟实时的数据分析应用。其定位不仅是一个 SQL 数据库系统,还提供流处理能力:使用流数据执行连续查询,并以物化视图的形式动态维护结果。另外,RisingWave 采用了分层架构,建立在现代云基础设施之上,利用云资源为用户提供成本和性能的细粒度控制。
这个架构最大的特点在于,资源是无限的。由于有无限的资源,性能就不会成为特别大的问题——只要添加资源,性能就能提到提升。但资源是收费的,设备也是收费的,我们希望能在保证用户性能的前提下,降低整个系统的成本,让普通用户以较为低廉的价格使用我们的服务,这也是我们的核心设计理念。
这与编程语言的选择没有太大关系,开发一款数据库可以使用各种各样的语言,比如 C++、Rust、Java,Scala 等,一些交易系统可能还会考虑 Haskell。不过即便是二十年前,也很少有人用 Java 、Basic、Python 这类语言构建数据库,主要因为这些语言的运行效率和性能均不高。
因此,我们主要希望选择一门高性能的编程语言,而所谓的高性能语言不外乎 C++、Rust 或者一些小众语言,如果又想被用户广泛接受,那基本上就是 C++ 和 Rust。
提问:据了解,你们团队最初选择的是 C++,还集结了多位拥有 10 年以上经验的 C++ 工程师。当初你们是看中了 C++ 的哪些特质,还是说你们只是遵从了市场上大部分数据库系统的选择?
吴英骏: 我本人比较擅长 C++,不管是读博期间还是创业之前开发的所有数据库都是用 C++ 编写的,我没有用其他任何语言写过项目。
创业之初,有人提议使用 Rust,理由是 Rust 很火。但在我看来,这算不上一个充分理由,我们又不是想成为网红,选择一门语言不能仅仅是为了火,我们需要考虑哪种语言适合团队,以及数据库领域的通用语言是什么。在数据库领域,虽然 TiDB 的存储引擎 TiKV 是用 Rust 写的,但这不足以证明用 Rust 写的数据库系统都能成功,相反绝大多数成功的数据库系统都是用 C++ 编写的。
从招聘的角度来看,我们肯定希望招募到数据库领域的专家,而拥有多年数据库领域经验的专家大多来自如今的主流数据库提供商——这些数据库也基本都是用 C++ 写的。
相较而言,Rust 是一门比较年轻的语言,缺少重量级项目。尽管实际上很多项目都使用了Rust,其中一些还是相对流行的项目,但还算不上重量级的大工程,生态系统或多或少有些不足。
综上,最终我们决定使用 C++ 作为主要开发语言。
提问:你们团队已经在这个项目上投入了 7 个多月,你也提到时间对于创业公司而言是非常宝贵的,是因为什么契机让你们觉得不重写不行了?
吴英骏: 首先,C++ 比较常见的问题是内存泄漏,但这类 Bug 比较容易修复,我们觉得可以忍。其次,依赖管理很痛苦,虽然 CMake 工具可以自动配置 C++ 项目的编译,但使用起来还是很麻烦,我们仍然需要手动配置并安装依赖库;STL 库缺乏对一些现代编程工具的支持,依赖的社区项目大多数还缺乏长期支持。最后,我们招聘到的成员 C++ 水平参差不弃,每个人都有自己的风格,非常难以统一,导致阅读代码的难度过大,审查代码更是劳心劳力。随着越来越多人员的加入,C++ 问题暴露得越来越频繁,在此期间不断有工程师提出是否可以考虑用 Rust 重写。
另外,流式数据库通常用于处理对延迟非常敏感的关键性任务。因此,构建 RisingWave 的编程语言必须满足以下要求:保证零成本抽象,不能有性能上限;不需要运行时垃圾收集,可以控制由内存管理引起的延迟峰值。
起初,我们并不想更换语言,毕竟已经写了这么久。但最终我们决定,如果支持用 Rust 重写的工程师可以成功重写一个独立的模块,我们就考虑重写整个数据库。与此同时,我也想起之前在 AWS Redshift 工作中遇到的一个 Bug,三个人不断调试了两周都无解,最终发现是内存泄漏的问题。如果现在项目继续下去很可能也会遇到类似的情景,假设那时产品已经有了很多用户,我们还需要因为这种内存泄露的问题调试许久,那就得不偿失了。所以就在那个时候,我们开始认真考虑是否要用 Rust 重写。
经过慎重评估,我们需要花费大约两个月的时间就可以用 Rust 重写原来七个月写的代码,这个时间差主要是由于项目的逻辑框架已在项目前期梳理清楚。暑假期间公司招了大量实习生,人手比较充足,且很多实习生都有 Rust 的基础,这些都提升了重写的速度。最后,经过全公司的表决投票,我们开始重写。
在替换的过程中,我们选择逐个模块替换,这也保证了整个过程不会出现很严重的问题。
提问:用 Rust 重写以后,C++ 代码风格不统一的问题得到解决了吗?
吴英骏: 风格不统一的问题肯定不是用 Rust 就能解决的,但相对 C++ 会有很大程度的改善。C++ 中关于指针等的写法很难统一,还容易造成安全性的问题。
提问:C++ 中一些语言层面的缺陷由来已久,在使用 C++ 作为主要开发语言之前,你没有遇到过上述问题吗?
吴英骏: 我之前也遇到过,但在我上学期间,Rust 还不完善,用户很少,因此不会考虑到用 Rust 去开发数据库。此外,我之前接触的数据库都是比较成熟的产品,比如 IBM DB2,所以我的大部分工作时间都在调试,很难有精力和时间去重写一个诞生于几十年前的数据库。
在大型企业内部,只有不太重要的项目或者用户数量不多的项目才有可能被重写,否则就需要投入大量的精力和资源。对于起步阶段的创业公司来说,还是有机会重写的,一旦面对客户交付的压力,重写就不太可能了。
提问:在重写之前,系统已经完成了多少?
吴英骏: 简单来说,框架已是比较清晰的水平。重写不至于发现之前的 Bug,但通过重写,我们确实会考量各个部分设计的合理性。
提问:Rust 有哪些有优势?
吴英骏: 首先,安全性绝对是一大优势,这对数据库项目非常重要。其次,包管理需要的工作量非常少,C++ 有非常多的库,包管理非常复杂,你需要花费几个小时才能搞清楚如何在 CMake 里面配置一个包管理工具,即便在配置之后也需要花费很多时间,比如无法安装,还可能遇到重名的问题(其他项目中使用的变量名称与我们库中的名字重合了),这些问题都需要手动解决,而且改起来费时费力。
提问:重写前后的收益情况如何?
吴英骏: 一句话总结:收益巨大。从收益比的角度看,我们损失的是时间,因为分段重写大概花费了一个月左右,但这些时间并没有白白浪费,这个过程让我们又反思了一遍不同模块的设计思路,改掉了其中不合理的部分。对数据库系统而言,这是一个长周期的项目,早期孵化阶段时间的宝贵程度和正式上线后肯定是有区别的。当对象是直接用户时,数据库系统出现任何问题都是不能忍的。
我们收获的是系统更加稳定、安全,且代码清晰,尤其是包管理部分有非常大的提升。此外,Rust 本身在高速发展中,整个社区非常有活力,提问基本都能够得到及时回复,这是 Rust 生态系统带给我们的优势。
提问:重写之后,原来那批 C++ 工程师都自学了 Rust 吗?
吴英骏: 团队中的部分工程师之前就掌握了 Rust,只是未在工作中使用,这部分工程师还是比较容易转换的。我们也专门让一些工程师评估从零开始学 Rust 需要多久,绝大多数工程师基本能够在一个月之内掌握 Rust,但还达不到全面掌握,只是可以使用 Rust 写一些代码。
整个过程比较顺利,因为部分工程师会利用业余时间自学 Rust,并将经验传播给其他人,这是非常重要的。我认为,如果公司决定重写,那么公司内部必须有一到两位,甚至更多位拥有 Rust 实战经验的工程师,或者至少愿意利用业余时间学习,并将经验传授给其他人,这可以降低整个公司的学习难度,毕竟 Rust 的学习曲线是比较陡峭的。
提问:拥有其他编程语言基础对于学习 Rust 有影响吗?
吴英骏: 会有差异,而且比较明显。对于其他语言,比如 Python,最大的特点是简化编程,开发人员不需要考虑内存管理等问题,但 Rust 需要这方面的基础,所以拥有不同的语言背景,对于学习 Rust 的成本有不同的影响。
提问:Rust 一直存在编译时的问题,你们有感受到吗?
吴英骏: Rust 确实存在编译时问题,但 C++ 的编译相对也很慢,所以目前还可以忍受。如果编译时间过长,工程师会定期查看编译过程,并尝试是否有办法可以缩短这个时间。
提问:你会建议什么类型的公司或者业务团队在什么情况下选择重写代码库?
吴英骏: 如果是大型公司内部选择重写,大概率表明项目本身不是那么重要,或者是核心项目的边缘模块,用户没有那么多、公司又有钱、有资源、有人力,这种情况下可以考虑重写。对于创业公司而言,早期还有精力重写,一旦用户量上来就会面临交付压力,基本不太会做这种决定。
此外,你需要搞清楚换编程语言的理由,出于性能、安全性或者其他原因,而不只是因为某种语言很火。以数据库领域为例,现在很多成功的数据库诞生距今已有十年以上,经历了长时间的磨炼,其实转 Rust 的需求并不大。总的来说,我认为考虑实际的需求非常重要,你需要综合考虑再做决定。
提问:你觉得目前 Rust 的生态环境如何?
吴英骏: 整体来看 Rust 的生态环境比较不错,主要问题在于缺少大型项目验证,比如 Go 最成功的项目是 Kubernetes。但我们也看到不少科技公司考虑使用 Rust 重写某些服务,比如 InnoDB,也看到很多公司加入了 Rust 基金会,比如 AWS、Google、Facebook 等。我相信,有了这些公司的长期支持,未来会出现一些非常不错的项目,Rust 会变得越来越好。
提问:选择用 Rust 重写与团队规模和状态之间是否有关系?
吴英骏: 我觉得重写和团队规模的关系不是很大,但我更建议年轻的团队选择 Rust,当然这也因人而异。至于最终是否要转,也要考虑团队大多数人的意见,因为在学习了一段时间之后,发现还是没有熟练掌握 Rust 可能会有很强的挫败感,这需要团队成员的共同努力,仅凭兴趣很难做好。此外,仅凭兴趣决定创业以及对外提供商业化服务,这也是非常不负责的。