随笔·阅读约 1 分钟·
为什么 Discord 从 Go 迁移到 Rust

为什么 Discord 从 Go 迁移到 Rust

Go 的 GC 延迟在实时场景下成为瓶颈,Rust 的无 GC 内存模型让 Discord 实现了稳定的毫秒级延迟。

原文来源:Discord — Discord 解释为什么把关键服务从 Go 迁移到 Rust,核心原因是 Go 的 GC 延迟无法满足实时通信的严格要求。

Discord 是全球最大的实时通信平台之一,每天处理数十亿条消息。他们的技术栈选择一直备受关注——从早期的 Python 到后来的 Go,再到现在的 Rust。这个迁移路径不是追逐技术潮流,而是随着规模增长被迫做出的工程决策。

问题:Go 的 GC 延迟

Discord 的 Go 服务在处理实时消息时遇到了一个核心问题:垃圾回收(GC)导致的延迟峰值。

Go 的 GC 是并发的,理论上不会暂停整个程序。但在高内存压力下,GC 需要扫描大量对象,这个过程会占用 CPU 资源,导致处理延迟突然增加。对于普通 Web 服务,几毫秒的延迟波动可以容忍。但对于实时通信,用户能感知到 50ms 以上的延迟变化。

Discord 的具体数据:Go 服务的 P99 延迟在某些场景下会跳到数百毫秒,而他们的目标是稳定在 10ms 以内。优化 GC 参数、减少分配、对象池化——这些手段都试过了,但无法从根本上解决问题。

为什么选 Rust

Rust 的核心优势在于无 GC 的内存安全模型。内存管理在编译期就确定了,运行时不需要垃圾回收,因此没有 GC 暂停。

这个特性对 Discord 的场景至关重要:

可预测的延迟 — 没有 GC 意味着没有意外的延迟峰值。P99 延迟和 P50 延迟的差距可以控制在很小范围。

内存效率 — Rust 的零成本抽象让内存布局更紧凑,缓存命中率更高,同样的硬件能处理更多并发。

并发安全 — 所有权系统在编译期防止数据竞争,多线程代码不需要运行时锁检查,进一步降低延迟。

迁移过程

Discord 不是一次性重写所有服务,而是按优先级逐步迁移。

第一步:状态服务

用户在线状态、频道成员列表——这些需要实时同步的数据最先迁移。Go 服务在这个场景下的 GC 问题最严重,迁移到 Rust 后延迟下降了 10 倍。

第二步:消息路由

消息从发送者到接收者的路由逻辑。Rust 的无锁数据结构让这个环节的吞吐量提升了数倍。

第三步:媒体处理

语音和视频数据的处理。Rust 的内存安全特性在这里特别有价值——媒体处理涉及大量二进制数据,C/C++ 容易出内存错误,Rust 在保持性能的同时消除了这类风险。

迁移成本

从 Go 迁移到 Rust 不是没有代价的。

开发速度 — Rust 的学习曲线更陡峭,编译器的严格检查让初学者频繁遇到所有权错误。Discord 的工程师花了数月时间适应 Rust 的开发模式。

代码量 — Rust 的显式错误处理和生命周期标注增加了代码量。同样的逻辑,Rust 实现通常比 Go 长 20-30%。

生态差距 — Go 在网络编程生态上更成熟,很多库开箱即用。Rust 的生态系统在快速增长,但某些领域仍然需要自研。

Discord 认为这些成本是值得的,因为性能收益直接转化为用户体验。对于实时通信平台来说,延迟就是核心竞争力。

对其他团队的启示

Discord 的经验不是所有团队都应该复制。迁移到 Rust 的决策取决于几个条件:

延迟敏感度 — 如果你的服务对延迟不敏感(如后台处理、批处理任务),Go 的 GC 问题不会成为瓶颈,迁移收益有限。

规模 — GC 问题在高内存压力下才显现。小规模服务可能永远遇不到 Discord 遇到的问题。

团队能力 — Rust 需要投入学习时间。如果团队没有系统编程背景,迁移成本会更高。

替代方案 — 在迁移之前,应该穷尽 Go 的优化手段。Discord 是在尝试了所有 GC 优化后才决定换语言的。

总结

Discord 从 Go 迁移到 Rust 是一个特定场景下的工程决策,不是对 Go 的全盘否定。Go 仍然是大多数后端服务的优秀选择——开发效率高、生态成熟、并发模型简单。但在对延迟极度敏感的实时通信场景,Rust 的无 GC 模型提供了 Go 无法达到的可预测性。

这个案例的价值在于展示了技术选型的权衡逻辑:没有最好的语言,只有最适合特定约束的语言。当约束变化时(从普通 Web 服务到实时通信),最优选择也会变化。

分享到
微博Twitter

© 2026 四月 · CC BY-NC-SA 4.0

原文链接:https://aprilzz.com/ramble/discord-go-to-rust