Discord 如何把后端与基础设施开发迁到云端
原作者:Denbeigh Stevens;原载 Discord Engineering & Developers,2024 年 2 月 22 日。本文为中文译编,编者补注与原作者叙述分开标示。

编者说明:这是一篇发表于 2024 年的工程回顾。文中“我们”指 Discord 团队;2020 年接触 Coder、2023 年切换 V2 等时间线保持原样。它讨论的是后端与基础设施开发,不意味着 Discord 的所有客户端开发都已迁往云端,也不代表今天各产品版本的表现。
先解决环境问题,开发工具才能跟上团队增长
构建和维护 Discord 是一项复杂的工作。我们的开发集中在一个多语言单体仓库中,最活跃的语言包括 Python、TypeScript、Rust、Elixir 和 C/C++;产品则覆盖 Android、iOS、macOS、Windows 和 Linux。
内部开发者体验团队负责软件开发生命周期大约前三分之一的工作:构建和维护 IDE 体验、管理开发环境、提供构建、开发和测试工具、扩展与维护 CI 基础设施,以及负责变更管理流程和相应工具。本文聚焦其中一件事:借助 Coder,把所有后端与基础设施开发迁移到基于 Linux 的云开发环境。
过去几年,Discord 工程团队规模增长到原来的三倍以上。公司采用混合办公模式,在旧金山和荷兰设有办公室,而工程师主要远程工作。多数开发者使用 MacBook。在采用远程开发机以前,我们确保工程师可以在 Mac 和 Ubuntu 上完整启动 Discord,并自建工具,通过 Homebrew 配置笔记本。
问题是,一次 brew upgrade 就可能让开发者无法继续工作。我们把所有软件包以及传递依赖都固定到明确版本,解决了不少问题,却让随意安装其他软件包变得困难。后来我们改用 Nix 安装系统依赖,让工程师仍能根据需要使用 Homebrew。
本地服务编排也在演进:最初是 Makefile 和 Procfile,随后需求超出了这套方式的承载能力。我们尝试过 Docker 和 docker-compose,但没有选用。原因并非一种工具适用于所有情况:当时 Docker for Mac 的性能不足,构建与重新构建循环中的额外阻力,使我们继续寻找更快、更简单的方案。最终,团队迁到基于 Supervisor 的系统,并开发了便于定义、启动服务及依赖的工具。
开发循环里不用容器,也有相应代价。工具团队必须维护两套不可复现的环境,频繁排查少见且因人而异的问题,帮助工程师解除阻塞。随着公司继续扩张,我们意识到,应该把精力集中在一套 Linux 开发环境上。这促使我们研究云开发环境,并最终评估 Coder。
云开发环境带来的能力,以及无法消失的延迟
把开发迁到云厂商托管的虚拟机,可以获得不可变性、可复现性、可配置性、更强的安全性和内置的身份访问管理(IAM)等能力,也能使用更多自动化工具管理环境。然而,只有编辑器与日常开发循环足够顺畅,云开发环境才值得采用。当时 VS Code 的 Remote Development 扩展已提供稳定、扎实的体验,而 Discord 大多数工程师都使用 VS Code,这让我们有信心开始迁移。
可复现且一致的环境,是稳定体验的基础。完全不可变的环境在理论上很理想,实际使用却并不现实。我们选择挂载并保留 /home,使它在重启后仍然存在。这样,开发者回来就能从原来的进度继续:代码仓库、dotfiles、个人工具以及工作区定制,都有地方保存。
这偏离了部分不可变原则,也会带来状态累积的问题;好处是模板与镜像可以更新,而不必彻底重建整个工作区。团队在标准环境和个人使用习惯之间作了这样的折中。编者补注:持久目录仍然需要备份、访问控制和生命周期管理,保留 /home 不等于保留了一份可恢复、已验证的备份。
云开发也有缺点。远端无法在所有场景下复制 localhost 的响应速度,SSH 路径上的额外延迟有时很明显。网络不稳定时,工程师遇到过延迟增加、连接断开和整体体验下降。大型 HTML 与 JavaScript 包在网络上传输,也会拉长最关键的保存与重建循环。
因此,许多工程师更愿意在本地笔记本做前端开发,在远程机器做后端开发。一旦某项修改同时涉及 API 和 UI,就需要维护本地、远端两份仓库,或在两台机器间同步代码。代码究竟在哪一边、哪边是最新状态,由此成为新的认知负担。即便存在这些取舍,我们仍认为收益大于代价。
从 Kubernetes 容器工作区到虚拟机
我们在 2020 年末开始接触 Coder。那时对方工程团队还很小,也经常使用 Discord。早期产品完全基于 Kubernetes,这对大量使用 Kubernetes 的 Discord 很有吸引力。考虑到自建同等功能所需的时间与精力,评估 Coder 是自然的选择。
原作者当时还提到,Coder 提供了他们预期的各项功能;对方团队近期从头重建产品,解决了早期合作中遇到的许多问题。
但把 Kubernetes 和容器作为主要开发环境,让我们遇到了不少问题。开发 Discord 需要一个复杂、组件众多的环境。在 Sysbox 环境中开发时,多层虚拟化让维护与排障变得困难;团队还遇到资源互相干扰的“吵闹邻居”、延迟尖峰,以及高于预期的网络延迟。
2023 年,我们迁移到 Coder V2,可以直接向开发者交付虚拟机,大部分问题因而得到缓解。V2 的另一项变化是重写网络栈,借助 Tailscale 和 WireGuard 改善连接稳定性、安全性与性能。虚拟机让我们获得完整的主机控制能力,也显著简化了架构。
迁移后,工程师普遍反馈开发更快、更流畅。作者报告,关于高延迟与连接断开的支持工单和提问不再出现。编者补注:这是该团队当时的观察,并非适用于所有网络条件的性能保证;本文也没有对这组体验结论进行独立基准测试。
迁移不仅是技术工程,也是工作方式的改变
从本地 MacBook 到 Coder 的过程,包含大量学习和调整。高度简化后的计划分为三步:
- 先把默认体验做扎实,让常规路径能够顺利工作。
- 逐步扩大采用范围:先由少量开发者试用,收集具有代表性的反馈,再进入公开测试。
- 设定最终切换时间,配齐文档、培训与支持渠道,然后停止支持 MacBook 上的后端开发。
我们先完成看似“容易”的部分:创建开发容器,安装系统依赖,配置用户账号、权限和既有软件。尽早投资一部分内部自动化,有助于缩短反馈循环,提高这一阶段的推进速度。
之所以给“容易”加引号,是因为影响整个工程组织的迁移,难点往往在人。我们必须理解大家会失去哪些熟悉的体验,需要学习什么,以及哪一段最令人难受。团队做了访谈,尽早收集反馈,也亲自使用新的环境。
为了推动更广泛的采用,我们从不同部门邀请了一批热心开发工具的推动者。他们试用环境并持续反馈。不同岗位的日常开发循环与需求很重要:这种多样性让我们发现了许多单一团队不易遇到的问题,并与早期测试者逐项解决。我们还比较了不同构建工具,进行了网络负载测试,确认常用开发循环仍能正常且高效地工作。编者说明:本段所述的构建工具比较、网络负载测试与开发循环检查均为原作者团队的工作,本稿未重复执行。
我们的想法是:如果工具确实改善了工程体验,开发者自然愿意采用。最终切换日期仍然必要,但我们希望体验足够有吸引力,让多数人主动迁移。本地 MacBook 出问题时,我们也会建议工程师试试 Coder;令人放心的是,愿意尝试远程环境的人不少。
Apple M1 的出现加快了时间表。新笔记本开始交付后,团队发现后端栈在新硬件上存在一些问题;Rosetta 能帮助部分应用,无法覆盖全部应用。当可采购的新硬件只剩 Apple Silicon 时,我们决定提前进入第三阶段,停止支持基于 macOS 的后端开发。
容器中的“开发机”暴露了哪些边界
我们学到,在 Kubernetes 容器里模拟一台完整开发机并不轻松。例如,团队不能使用特权容器,于是必须寻找其他办法修改开发所需的内核参数。Scylla 等应用需要内核模块或参数调整,这就成为实际障碍。我们当时的解法是在每个节点部署一个特权守护进程,设置底层主机的内核参数。
编者补注:这是历史架构中的受控机制,不是建议读者直接添加节点级特权服务。它把权限提升到了宿主机边界;评估类似方案时,需要明确谁能请求参数变化、允许修改什么、如何审计与回滚,并考虑同节点其他工作负载受到的影响。原文没有给出实现代码,本文不补造可部署配置。
我们也再次认识到响应速度的重要性。如果人打字比系统渲染还快,工作流就会被打断。顺畅的入门体验同样关键,尤其要照顾不熟悉命令行的开发者。团队补充了文档、培训、录屏视频和功能较齐全的默认 dotfiles,帮助没有多年工具配置积累的人上手。虽然在这些最后一公里的工作上投入很多,仍觉得不够满足每个人。
如果重来一次,先把诊断与沟通做得更好
迁移后最突出的痛点,是网络延迟和连接断开。工程师分散在美国各地以及其他地区,很难事先覆盖最差的网络条件。团队曾利用早期 Coder 的 satellite 功能,在不同地区部署 Kubernetes 集群来减少延迟,但部分开发者仍然体验不佳。
回头看,我们应该更早建设诊断工具,以便问题出现时,能够在不同网络条件下理解、定位和排查问题。后来这些工具确实做出来了,但在迁移完成前缺少它们,使团队一度无法充分了解实际情况。重建网络栈和切换虚拟机解决了大部分问题;如果早些关注诊断,就能更早认识用户体验。
任何大规模迁移,都需要对沟通和文档作显著投入。要求所有工程师改变完整开发流程,是很大的要求。我们虽然通过全员会议介绍变化、提前发出通知,并进行了很长时间的测试,仍认为沟通可以做得更充分。
这条路径经历了两次迁移——从 Mac 到 V1,再到 V2——投入也相当可观。原作者在回顾中感谢与 Coder 的合作,并认为它为分布各地的工程师带来更一致、可靠的开发环境;尽管投入重大,团队仍愿意再作同样的选择。文章还提到项目在疫情前已启动,与后来更加分散的工程团队形成了合适的衔接。
编者归纳:这个案例的可迁移经验,是同时设计标准环境、个人状态、网络诊断和组织切换过程。云开发不会让本地前端同步、云资源费用、权限治理或持久目录维护自动消失;这些都是架构选择的一部分。
来源:How Discord Moved Engineering to Cloud Development Environments,Denbeigh Stevens,Discord,2024-02-22。版权归原作者及权利人所有;本文的翻译与转载依据另行取得的授权使用。
编者说明:本文记录 Discord 作者团队的迁移经验与其对 Coder 合作的评价,不是对 Coder 产品的独立评测。











暂无评论内容