阿里、蚂蚁、晟腾、中科加禾精彩分享 AI 基础设施洞见,现购票可享受 9 折优惠 |AICon 了解详情
写点什么

连 1.0 版本都没有,Uber 为什么会采用这样一项新技术?

  • 2022-06-06
  • 本文字数:4610 字

    阅读完需:约 15 分钟

连1.0版本都没有,Uber为什么会采用这样一项新技术?

本文最初发布于 Motiejus Jakštys 的个人博客。

免责声明:我在 Uber 工作,我的一部分职责是将zig cc引入公司。但这篇文章是我的观点,与 Uber 无关。

我日前在 Zig 的一场交流会上作了题为“Uber 引入 Zig”的演讲。本文从技术和社交两方面简单介绍了“Uber 是如何使用 Zig 的”,而主要的篇幅是介绍“我把 Zig 带到 Uber 的经验”。


本文要点:


  • Uber 使用 Zig 来编译其 C/C++代码。现在,Uber 只在Go Monorepo中使用bazel-zig-cc,但计划尽可能地将zig cc推广到其他需要 C/C++工具链的语言。

  • 与其他工具链相比,zig-cc 提供的 C/C++工具链的主要优势是:glibc 版本可配制与 macOS 交叉编译。

  • Uber 没有任何使用 zig-the-language 的计划。

  • Uber 与 Zig 软件基金会(ZSF)签署了一份支持协议,以优先修复我们提交的 Bug。ZSF 的财务报告有披露了合同额。

  • 感谢我的团队、Go Monorepo 团队、Go 平台团队、我的主管、财务、法律,当然还有 Zig 软件基金会,是他们让这种关系成为现实。到目前为止,这种关系已经带来了丰硕的成果。


Uber 技术栈简介

Uber 于 2010 年创立,已拥有超过 150 亿次的出行记录,为此,他们实现了很多很酷的创新技术。Go 和 Java 是通用服务器端语言,Python 和 Node 应用于特定的情况(如 Node 用于前端,Python 用于数据分析/ML)。C++被用于一些底层的库。在后端代码中使用其他语言的情况很少。


我们的 Go Monorepo 比 Linux 内核还要大,有几千名工程师在开发和维护。总而言之,很大。

Uber 是如何使用 Zig 的?

Abhinav Gupta是我们的来自 Go 平台团队的同事,其实他描述得比我好:我理解我们只是在使用 Zig 的 C 工具链,而不是将其作为语言使用。Zig 支持基于 C 的代码的交叉编译,能减少对系统 C 编译器的依赖。


Uber 技术栈发展历程

2018 年之前,Uber 的 Go 服务都有单独的存储库。2018 年,我们开始将这些服务大规模地迁移到 Go Monorepo。我的团队参与了第一波迁移——我仍然记得那有多复杂。

2019:寻求一个封闭式的工具链

当时,Go Monorepo 已经使用了一个封闭式的 Go 工具链。因此,用于构建 Go Monorepo 的 Go 编译器不会受系统上安装的编译器影响(如果有的话)。因此,无论在哪个环境下构建,都会使用相同版本的 Go。Bazel文档对此做了很好的解释


创建于 2019 年,没有太多变动。


C++工具链是一个编译 C/C++代码的程序集。不可避免地,我们的一些 Go 代码要使用CGo,所以它需要一个 C/C++编译器。然后,CGo 将 Go 和 C 部分链接成最终的可执行文件。


从 Go Monorepo 创建伊始,C++工具链就不是封闭式的:Bazel 会使用它在系统上发现的任何东西。也就是说,在 macOS 上使用 Clang,在 Linux 上使用 GCC(无论什么版本)。在 Bazel 中创建一个封闭式的 C++工具链是一项很大的工作(对于我们的 Go Monorepo 来说,需要花费数月时间),没有迫切的需求,也没有足够的痛苦,我们还无法接受做这样一件事。


现在,我们看下非封闭式 C++工具链的局限性:


  • 不能交叉编译。所以,如果需要 CGo 的话(我们的许多服务都需要),我们就无法在 Mac 上编译生成 Linux 上的可执行文件。这可以通过......而不是交叉编译来解决。

  • CGo 的可执行文件将链接到系统上发现的 glibc 版本。也就是说,在升级操作系统时(数月的努力),构建机群必须最后升级。否则,如果构建主机上 glibc 的版本比生产主机上的新,那么生成的二进制文件将链接到较新的 glibc 版本,就会与生产主机上的旧版本不兼容。

  • 我们无法使用新的编译器,即使它提供了更好的优化功能,因为我们在构建机群上运行的是旧版本的操作系统(只向后迁移编译器,而不迁移 glibc,本身就有风险)。

  • Go 的新版本的官方二进制文件在构建时使用的 GCC 版本,比我们的一些构建机器上的新。在这些机器上,我们不得不通过从源代码编译 Go 来解决这个问题。所有这些问题都很令人恼火,但不足以让我们在工具链上进行投资。

2020 年 12 月:需要 musl

我在做一个与 Uber 无关的小项目。该项目是用 Bazel 构建的,并使用了 CGo。我希望我的二进制文件是静态的,但 Bazel 并没有让这个过程变得简单。我花了几个晚上基于musl.cc创建了一个 Bazel 工具链,但没走多远,因为当时我无法深入理解 Bazel 的工具链文档,而且也没有找到一个好的示例可以参照。

2021 年 1 月:发现zig cc

2021 年 1 月,我发现了 Andrew Kelley 的博文“zig cc:一个功能强大的GCC/Clang替代品”。我推荐你读一下这篇文章;它改变了我对编译器的看法(也有助于你更好地理解本文接下来的内容,因为我是讲给 Zig 追随者听的)。综观 Andrew 的文章,zig cc有以下优势:


  • 完全封闭的 C/C++编译器,压缩包只有大约 40MB。这比 Clang 的标准发行版要小一个数量级。

  • 可以链接到通过命令行参数提供的 glibc 版本(例如,-target x86_64-linux-gnu.2.28将以 x86_64 Linux 为编译目标并链接到 glibc 2.28)。

  • 主机和目标平台是解耦的。不管是什么主机,针对目标平台linux-aarch64darwin-x86_64的设置都是一样的。

  • 与 musl 链接“只是一个不同的 libc 版本”:-target x86_64-linux-musl。我开始摆弄zig cc。我随便编译了一些程序,报告了一些问题。我想过把它做成一个bazel工具链,但有很多拦路的 bug 或缺失的功能。其中之一就是缺少 Bazel 所依赖的zig ar

2021 年 2 月:请求关注

向Zig报告了Bug。一个星期都没有动静。我每月捐 50 美元,希望“Zig 的人”能优先处理我所报告的问题。接着又是一个星期的沉默。然后我在#zig:libera.chat中扔了一枚炸弹:


<motiejus> 捐赠后,有什么规约可以用来“申请”开发时间吗?<andrewrk> ZSF只接受不附带任何条款的捐赠。<andrewrk> 你是从哪里获得了不同的印象吗?
复制代码


当时,我希望无论谁注意到这段对话都立即忘掉它。好吧,一年多以后,我又把这段话写在这里,看着玩吧。

2021 年 6 月:bazel-zig-cc 和 Uber 的 Go Monorepo

2021 年 6 月,Adam Bouhenguel创建了一个可以工作的bazel-zig-cc原型。基本功能没问题,但仍然缺少一些特性。后来,Andrew 实现了zig ar,这是一个真正可用的 bazel-zig-cc 所缺少的最后一块拼图。我集成了zig ar,完善了文档,并在Zig邮件列表中宣布了我创建的 bazel-zig-cc 分叉。至此,它对我的小项目是有效的。


在公告发布几周后,我为 Uber 的 Go Monorepo 创建了一个“WIP DIFF”:只是按照我的上线说明,天真地将其提交到我们的 CI。几乎所有的测试它都没有通过。


将 bazel-zig-cc 加入 Uber 的 Go Monorepo。


大部分失败都是由系统库依赖导致的。关于这一点,很明显,要想真正搭载 bazel-zig-cc 并编译所有的 C/C++代码,需要巨大的投入来消除对系统库的依赖,并偿还大量的技术债务。

2021 年底:回顾

  • Uber 有很多地方可以从一个封闭式的 C++交叉编译器中受益,但由于需要大量的投资,再加上没有足够的理由,所以没有获得资助。

  • bazel-zig-cc 有点用,但 bazel-zig-cc 和 zig cc 已知都存在 Bug。

  • 我无法实现必要的修改或 Bug 修复。所以,我试图实现zig ar,LLVM ar的一个小前端,但失败了。

  • 如果确定一个问题是 Zig 的问题,那么我们就无法预知它什么时候能引起 Zig 开发者的关注。有些问题几天内就得到了解决,有些则花了 6 个多月的时间,而捐款并不会改变zig cc的优先级。

  • Monorepo 上线差异(monorepo-onboarding diff)正在酝酿之中,等待时机。

2021 年底:Uber 需要交叉编译

我的任务是为 Uber 评估 arm64。撇开评估细节不说,我需要为 linux-arm64 编译软件。大量的软件!由于我们大部分的底层基础设施都在 Go Monorepo 中,我首先需要一个交叉编译器。


我终于有了一个实现交叉编译器的商业理由。现在,时间和金钱都可以投入了。“WIP DIFF”搭配zig cc是一个良好的开始,但距离终点还很远:团队不相信这是正确的事情,DIFF 更多的是一个原型。而且,要让 zig-cc 和 bazel-zig-cc 在任何情况下都可以使用,还有很多工作要做。


在一个大公司里引进这样的技术时,最重要的是风险管理。由于 Zig 是一项新技术(甚至连 1.0 都没有!),建议用它来编译我们所有的 C 和 C++代码很不寻常。我们应该做好至少十年内都使用它的计划。人们提了一些问题,并针对这些问题做了认真仔细的评估。为此,我真心感谢 Go Monorepo 团队,特别是 Ken Micklas,为这个未经证实的原型做了大量的工作和研究。

评估不同的编译器

我们需要一个交叉编译器,摆在我们面前的选项有两个:


  • grailbio/bazel-toolchain:使用普通的 Clang。没有风险。容易理解。显然,这是一个安全、恰当的解决方案。

  • ~motiejus/bazel-zig-cc:使用zig cc。有问题,有风险,不安全,不确定,没有人使用,但却是一个相当诱人的解决方案。与bazel-toolchain相比,zig cc额外提供了以下特性:

  • 可配置的 glibc 版本。使用grailbio,就需要 sysroot(本质上是一个带有系统库的 chroot,因此,程序可以与之链接),而这需要维护。

  • a working, albeit still buggy, hermetic (cross-)compiler for macOS.一个存在缺陷,但可以工作的封闭式 macOS(交叉)编译器。使用这两种方法中的任何一种处理 glibc 都没问题,然而,grailbio似乎不大可能编译到 macOS 上,更不用说交叉编译了。依赖开发者笔记本电脑上的系统编译器是不可取的,Go 平台团队亲身感受到了这一点,尤其是在 macOS 升级期间。


对于以 macOS 为目标封闭式工具链,选择的天平偏向了zig cc,连同它所有的缺陷、风险和不稳定性。


还有一个问题需要注意:我们知道,如果我们在重要的地方使用 Zig,会遇到问题,但又可能不具备解决这些问题的专业知识。作为一家大公司,我们该如何降低采用风险,确保严重的 Bug 及时得到处理?我们确信,ZSF 的出发点是好的:显然,如果我们发现并报告一个合理的 Bug,它就会得到修复。但是,怎么才能设定一个等待时间的上限呢?

金钱

50 美元的捐款无济于事,也许一份大的服务合同会有帮助?我四处打听,是否可以通过花些钱来降低“交叉编译器”的风险。获得管理层同意大约需要 10 分钟;起草、审批和签署合同大约需要 2 个月。


合同条款大致如下:


  • Uber 将问题报告到 github.com/ziglang/zig,并通知 Loris。

  • Loris 将其分配给 ZSF 的某人。

  • 解决问题。

  • 完成后,Loris 输入解决这个问题花费的时间。Uber 有权占用 ZSF 成员的时间。我们对 Zig 没有任何决定权或投票权。我们有权提出建议,但这些建议将和来自其他第三方的建议等量齐观。我们不能要求特殊权利,这在合同中有明确规定,我们也不希望那样。


合同签署了,电汇完成了,在 2022 年 1 月:


  • 我们与 ZSF 签订了服务合同,他们承诺优先处理我们提交的问题。

  • Go 平台团队承诺为我们的 C++工具链实现交叉编译和封闭。

合同金额是公开的,因为 ZSF 是非营利的。

2022 年及以后

2022 年 2 月,该工具链通过一个命令行标志(--config=hermetic-cc)做了限定。自此,你可以在 Uber 的 Go Monorepo 中调用zig cc了,不需要自定义补丁。


证明我们的提交队列登录了我的 WIP DIFF。


2022 年截至目前的时间线:


  • 今年 4 月,我在米兰演讲期间,我们向生产环境交付了第一个用 zigc-cc 编译的 Debian 软件包。

  • 今年 5 月,我们在所有的 Debian 软件包中启用了zig cc

  • 下半年,我们希望用zig cc编译所有的 cgo 代码,并将--config= hermatic -cc作为默认设置。

  • 下半年,我们希望将bazel- zigc -cc移到 github.com/uber 下。我们已经向 Zig 提交了一些问题,截至发稿时,所有的问题都已解决。有些是由 ZSF 单独处理的,有些则涉及面比较广,需要 ZSF、Uber 和 Go 开发者之间合作。

小结

我开始准备演讲,希望能给出一个大公司如何采用 Zig 的“运行手册”。然而,其实并没有什么“运行手册”;我为采用 zig-cc 所做的努力本可能会因为很多很多原因而失败。


回顾过去,我觉得要想获得成功,最重要的是在适当的时候有一个杀手锏特性。在我们的例子中,有两个:无需 sysroot 的 glibc 版本选择和交叉编译到 macOS。


原文链接:https://jakstys.lt/2022/how-uber-uses-zig/

2022-06-06 12:287769

评论 2 条评论

发布
用户头像
"交叉变异",好恐怖 😱
2022-06-13 09:05
回复
“编译”~哈哈,那处已修正
2022-06-14 10:44
回复
没有更多了
发现更多内容

分享一些常用的开源博客社区网站

兮动人

博客 开源社区

合并k个已排序的链表

二哈侠

Nodejs快速搭建简单的HTTP服务器详细教程。

百度搜索:蓝易云

node.js 云计算 Linux 运维 HTTP

【华秋干货铺】一文轻松搞定PCB叠层和阻抗设计

华秋电子

Android 架构模式如何选择

vivo互联网技术

mvc Compose MVVM 解耦 MVI

Linux系统安装gcc详细教程。

百度搜索:蓝易云

云计算 Linux 运维 服务器 GCC

Centos7系统中找不到yum及安装方法。

百度搜索:蓝易云

云计算 Linux centos 运维 yum

探索Linux命名空间和控制组:实现资源隔离与管理的双重利器

柠檬汁Code(binbin0325)

Linux 容器 namespace 底层原理 Cgroups

飞桨AI Studio可以玩多模态了?MiniGPT4实战演练!

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

TypeScript 玩转类型操作之字符串处理能力

小乌龟快跑

typescript 面试 前端

企业号 8 月 PK 榜,火热开启!

InfoQ写作社区官方

热门活动 企业号 8 月 PK 榜

未来前端框架将持续推进组件化开发

没有用户名丶

直播平台源码开发,信息收发功能搭建

山东布谷科技

软件开发 直播 源码搭建 消息发送 直播平台源码

火山引擎AB测试:广告实验深度打通巨量引擎,高效测试广告素材

字节跳动数据平台

大数据 A/B测试 对比试验 企业号 7 月 PK 榜 数字化增长

细数不懂Spring底层原理带来的伤与痛

java易二三

spring 程序员 Spring Boot 计算机 底层原理

解析游戏陪练app源码的开发与意义

山东布谷网络科技

游戏 开源代码 APP软件开发

零信任体系化能力建设(1):身份可信与访问管理

权说安全

工赋开发者社区 | 面向CPS的制造执行系统(MES)实验平台验证

工赋开发者社区

如何为Spring和Mybatis增加可逆计算支持

canonical

Spring Boot mybatis 低代码 可逆计算 Nop平台

面试官:说出 Java 中的 7 种重试机制

java易二三

编程 程序员 面试 计算机

特性快闪:使用 Databend 玩转 Iceberg

Databend

这次是运行在 Intel AIxBoard™ 开发板上的 TDengine 预测“未来”

爱倒腾的程序员

工赋开发者社区 | 复杂电子装备制造数字化工厂实现逻辑与实施步骤

工赋开发者社区

RLHF 技术:如何能更有效?又有何局限性?

Baihai IDP

人工智能 强化学习 白海科技 RLHF 大语言模型

2023 云原生编程挑战赛火热报名中!导师解析 Serverless 冷启动赛题

阿里巴巴云原生

阿里云 Serverless 云原生

在 Go 语言单元测试中如何解决 MySQL 存储依赖问题

江湖十年

golang Web 后端 单元测试 测试 单元测试

7月征文活动结果出炉,快来看看有没有你

InfoQ写作社区官方

热门活动 年中技术盘点

Spring AOP 中的代理对象是怎么创建出来的?

江南一点雨

Java spring

PoseiSwap:通过 RWA 的全新叙事,反哺 Nautilus Chain 生态

大瞿科技

活动回顾|火山引擎DataLeap分享:DataOps、数据治理、指标体系最佳实践(文中领取PPT)

字节跳动数据平台

数据中台 数据治理 抖音 DataOps 企业号 7 月 PK 榜

Linux系统安装MySQL详细教程

百度搜索:蓝易云

MySQL 云计算 Linux 运维 服务器

连1.0版本都没有,Uber为什么会采用这样一项新技术?_语言 & 开发_Motiejus Jakštys_InfoQ精选文章