七年Django换Rust:一台服务器干十台的活


技术迁移真实案例:三个月,一个人,砍掉90%服务器成本!

 我们换了套技术,服务器账单直接打了一折

Wasmer团队将一个运行了七年的Django后端用Rust完全重写。重写后,CPU从220核降至24核,内存从800GB降至64GB,数据库连接数减少3-5倍,查询延迟提升5-10倍。本文详细记录了迁移的原因、过程、遇到的坑以及可复现的经验,适合正在考虑后端技术栈迁移的团队阅读。

事情是怎么开始的

先说结论。我们把一个用了七年的后端系统整个重写了,最后的结果是服务器从220个CPU和800G内存降到了24个CPU和64G内存。这不是什么实验室数据,是线上真实跑出来的。简单算一下,资源用量少了百分之九十。不是优化了几个小地方,是整个推倒重来。

这事儿的起因特别无聊。我们的后端跑着跑着就胖起来了,胖到像一个人天天吃夜宵还不运动。刚开始没问题,七年前写的时候觉得挺好,功能都有了,管理后台也顺手。但是用户慢慢多起来之后,服务器就开始喘。最开始是内存报警,我们加内存。然后是CPU扛不住,我们加CPU。最后发现加硬件这招不好使了,因为你加到一定程度,钱花出去了,问题还在。

有一段时间我们监控面板上显示的数据让我自己都不敢信。正常业务流量下,后端吃了800多G内存,220个CPU核心。而且我们流量真不算高,不是那种双十一级别的量。这说明什么?说明代码写得再漂亮,架构上如果一开始没设计好,后面堆再多机器也是往无底洞里填石头。

原来的系统到底哪里不对劲

原来的系统是一个Django后端。Django本身不差,我们用了七年,该夸的地方得夸。管理后台特别好用,出问题了上去点两下就能改数据,开发速度快,迭代快。但问题也慢慢长出来了。

最核心的问题在数据库连接上。Django的ORM虽然支持async语法,但底层的数据库连接和游标不支持真正的异步。这在我们用了GraphQL之后就特别明显。GraphQL一次请求可能要查好多张表,这些查询在Django里是串行跑的,一个等一个。等到后面慢的请求堆起来,数据库连接数就飙上去了。我们数据库连接数经常几千个,这在关系数据库里是个大负担。

然后是类型安全的问题。Python的类型提示是好东西,但我们的依赖库太多了,很多库的类型标注不完整,或者是Any类型。这就导致类型检查形同虚设。你看着代码里写了类型,实际上传递过程中早就变了。我们另一个边缘服务是用Rust写的,Python后端和Rust边缘服务之间来回传数据,类型对不上的情况出现过好多次。

启动时间也是个麻烦。最慢的时候启动要一分钟多。一分钟能发生很多事情,比如容器编排平台觉得你这个实例挂了,又给你起一个新的,新的一分钟还没起来,平台再起一个。最后变成一堆实例都在启动,没有一个能正常接流量。

这些事情里有一部分是我们自己作的。我们团队没有人是真正的Python专家。团队主力都在Rust那边,Python后端就一个人看着。而且业务压力大,大家都是先上线再说,类型标注能省就省,代码结构能凑合就凑合。七年下来,这个后端变成了一个弗兰肯斯坦式的怪物,不同的人用不同的风格往上叠功能,没有人有精力去做大清洗。

为什么选了Rust而不是其他方案

决定用Rust不是因为Rust能解决所有问题。我们团队已经熟悉Rust了,边缘服务、运行时、包验证逻辑都是用Rust写的。如果后端也用Rust,整个团队都能看懂后端代码,出了事谁都能修。这叫降低“大巴因子”——别等哪天真被大巴撞了才想起来知识都装在一个人脑子里。

另外AI工具帮了大忙。2025年的AI已经能看懂Python代码并且翻译成Rust了,虽然不能无脑相信,但机械性的模型转换、CRUD逻辑、数据库映射这些东西,AI做得又快又好。我们一个人全职搞了三个月,配合AI,把七年的代码搬过去了。

还有一点是启动时间。Rust编译出来的二进制文件启动就是一秒钟的事儿。冷启动再也不是问题。

强调一下,这不是说Django不行。Django我们用了七年,前面六年都挺好。只是在第七年,我们的团队结构、技术栈、业务规模都变了,Django不再是最优解。我们也考虑过快用FastAPI加SQLAlchemy,那也能看到性能提升,但我们觉得不如趁这次重写,把架构一起理清楚。

新系统怎么搭的

新系统分成了好多小箱子。技术层面的有数据库访问、GraphQL层、缓存、用户权限管理、管理后台、异步任务。产品层面的有应用管理、博客系统、邮件发送。每个箱子各管一摊,边界清楚。

数据库层用了SeaORM。这是个异步的ORM,所有的数据库操作都是非阻塞的。配合Rust的async运行时,同一个请求里的多个数据库查询可以同时发出去,谁先回来谁先处理。这比Django的串行查快了不是一点半点。

GraphQL服务器用了async-graphql。这个库性能很好,但有个问题——我们的GraphQL schema太大了,编译一次要很久。我们给这个库提了PR,把大schema的编译时间缩短了百分之七十左右。开源的好处就是你遇到问题可以自己动手修。

任务调度从Celery换成了Apalis。Celery本身挺好的,但我们用Rust重写后端之后,再单独跑一个Celery的Python进程就太奇怪了。Apalis是纯Rust的任务队列,跟我们的二进制文件一起编译,部署简单,资源占用也低。

管理后台这块确实麻烦。Django的管理后台太方便了,Rust这边没有现成的。最后我们用AI生成了一个管理后台,服务端渲染,配上Tailadmin的组件。说实话做出来之后比Django那个还好用,界面也更好看。这算是意外之喜。

迁移过程是怎么走的

迁移不是直接拍脑门说“下周上Rust”就完事了。我们分了几个阶段走。

第一阶段,先把Python后端里那些必须改的地方改了。比如数据库索引、慢查询、N+1问题。这些不管换什么语言都得改。

第二阶段,让Python和Rust共存在一个代码仓库里。两套代码,同一套数据库。我们让AI帮忙验证,确保两个版本对数据库的读写结果完全一致。每次改数据库结构,两边的迁移脚本都要跑通,数据要一模一样。

第三阶段,新功能用两个语言同时写。Python版本先上线,Rust版本在边上跑,但不接生产流量。跑一段时间,对比两边的输出,发现问题就修。

第四阶段,把Rust后端部署到预发布环境。预发布环境用的是生产数据的副本,真实流量回放。我们在这个阶段跑了大概两周,确保没有回归问题。

第五阶段,切流量。先是百分之一的流量走Rust,没问题就百分之十,百分之五十,最后百分之百。

整个过程中,团队里每个人都参与了。有人帮AI生成的代码做Code Review,有人写数据库迁移脚本,有人做性能测试。不是一个人的英雄主义,是一群人配合。

中间遇到过一个坑。我们想要同时支持SQLite和PostgreSQL两个数据库。SeaORM本身支持,但有些类型只在PostgreSQL里有,比如网络地址类型。这些地方得手动处理,写条件编译。最后我们决定生产环境只用PostgreSQL,开发环境也用PostgreSQL,就不折腾双数据库支持了。

结果怎么样

直接看数字。

CPU从220个降到24个,少了百分之八十九。平均CPU使用率从百分之八十降到百分之三十,这个下降意味着CPU不再是一直满负荷跑,有余力处理突发流量了。内存从800G降到64G,少了百分之九十二。数据库连接数从几千个降到几百个,少了三五倍。

查询延迟,同样的查询,Rust比Django快了五到十倍。注意这个数据是我们还没加缓存的时候测的。等我们把缓存层加上去,应该还能再降一截。P95的API延迟从120毫秒降到了30毫秒,用户感知到的速度明显快了。

启动时间从一分钟多降到一秒,快了六十倍。这对容器编排特别友好,实例挂了秒级拉起,用户几乎无感知。

这些数字不是在实验室里跑出来的。我们对比的是同样流量模式下,迁移前后的生产数据。旧系统跑了几周,新系统跑了几周,同一个业务,同一个数据库里的数据,同一个用户群体。

账单变化是最直观的。服务器费用直接腰斩再腰斩。而且需要维护的机器少了,出故障的概率也小了。一个人看基础设施本来就很累,现在机器少了百分之九十,轻松多了。

也不是全是好事

Rust当然也有让人头疼的地方。

编译时间太长了。改一行代码,编译可能要好几秒。要是改了公共库的接口,整个workspace重编,喝杯咖啡回来还没编完。这对迭代速度是有影响的。Python那边改了就能跑,Rust这边改完要等编译。我们后来优化了编译配置,用了增量编译和sccache,好了一些,但还是不如Python快。

不能再随意跑动态脚本了。以前Django有manage.py shell,连上生产环境就能跑Python代码查数据、修数据,特别方便。Rust这边没有这种运行时环境。任何代码修改都必须走完整的发布流程。这逼着我们要更小心,代码变更之前想清楚,测试覆盖得更全。不能说这是坏事,但确实不方便。

还有刚才说的SQLite和PostgreSQL双支持的问题。虽然最后我们决定只用PostgreSQL,但设计的时候确实多花了一些时间。

另外要说清楚,这些性能提升不全是Rust的功劳。Rust的低内存占用、强类型、异步模型确实帮了大忙,但更大的功劳来自于这次重写把七年积累的架构债务清理掉了。我们把乱七八糟的依赖理清了,把混乱的边界划清楚了,把不必要的抽象删掉了。就算用Go或者Zig重写一遍,只要把架构理清楚,一样会有大幅提升。Rust只是给了我们额外的安全保证和零成本抽象。

能复制吗

如果你现在的项目也遇到类似问题,我的建议是先别急着换语言。先把架构问题理清楚。我们真正解决的问题不是Python慢,而是架构乱。乱到一定程度,换什么语言都救不了。反过来,架构清晰的情况下,用Python也能扛住不小的流量。

确定要换语言之后,选什么语言取决于团队。我们选Rust是因为团队已经会Rust了。如果你团队全是Go工程师,那用Go重写会更明智。语言只是工具,团队熟悉度才是效率。

AI在迁移里确实帮了大忙。但AI不能替代人做架构决策。AI可以翻译代码,可以写测试,可以生成文档,但它不知道业务边界在哪里,不知道哪些模块该拆开,哪些模块该合并。这些决策必须人来定。

还有就是不要追求一次性全量切换。两套系统共存,流量慢慢切,灰度发布,能随时回滚。数据库层要做兼容,让两个版本都能读写同一份数据。这样万一出问题,切回旧系统只需要几分钟。

管理后台的问题要想好。Django的管理后台真的太方便了,换成别的语言之后很难找到同样好用的替代品。要么自己造一个,要么接受没有管理后台的现实,全靠SQL命令行干活。我们选了自己造,花了不少时间,但最后效果不错。

总的来说,这次重写的投入产出比是值得的。三个月的时间,一个人的全职精力加上团队的配合,换来每年节省至少百分之九十的服务器成本,以及未来维护成本的大幅降低。代码更清晰了,类型更安全了,团队能看懂后端的人变多了,出问题能修的人变多了。这就是我们做这件事的真正收益。


本文基于Wasmer官方博客《Porting our Django backend to Rust improved the infra usage by 90%》改写,原作者为Wasmer团队。原文发布于2026年6月5日。