Rust 基地打完补丁就塌了?补丁日存档 bug,如实复盘

Facepunch Devblog 80 承认,星期四补丁最初服务器版本里有个存档 bug:跑了很久的服务器打上补丁后大量建筑倒塌,之后重启则没有问题。复盘没有给出机制、影响数与恢复说法,本文只写已知部分,把声音池化问题分开讲,并把事件转成补丁日流程教训。

Rust 基地打完补丁就塌了?补丁日存档 bug,如实复盘
本篇导航5 个章节

一位 Rust 服主在补丁日星期四给跑了很久的服务器打了补丁,再登录时,眼看着基地一座座塌了。Facepunch 在自己的复盘里承认了这个 bug,却从没公布过背后的机制。这种诚实本身就是教训。

Rust 商店图:标志位于树林间卫星天线剪影之上。Steam 商店官方图,不是倒塌现场图。

快速信息

  • Rust,Facepunch Studios 的生存游戏,事发时还在抢先体验阶段。

  • 来源:Facepunch Devblog 80,补丁日星期四翻车后的复盘文章。

  • Bug 本身:该补丁最初服务器版本里的存档 bug。跑了很久的服务器打上补丁后,大量建筑倒塌。

  • 没有继续坏的部分:之后重启没有问题,但这不等于什么都没丢。

  • 复盘没给出的部分:没有机制、没有影响数、没有恢复说法、没有具名作者、抓取到的文本里没有具体日期。

  • 同补丁的另一个问题是声音池化,属于未经测试的最后一天改动,后来通过更新禁用。它不是存档 bug。

  • 最后核实:2026年10月27日。

补丁日星期四,和一台跑了很久的服务器

Facepunch 在 Devblog 80 开头就直白地道歉:星期四的补丁坏了,团队沟通也不好。这就是整篇复盘的调子,细节之前先值得学这一点。作者写道,游戏当时还在 alpha 阶段,但这不是把什么都往主分支上扔的借口。最严重 bug 的触发条件很具体,复盘原话就是:如果你的服务器已经跑了一段时间,然后打上了这个补丁,大量建筑就会倒塌。它没说所有服务器、所有玩家或全新安装都会中招。它说之后的重启没有问题。把这句话读两遍,因为本文剩下的部分都绕着它转。

复盘从没解释过机制。里面没有存档格式变化、没有序列化不匹配、没有稳定性重算、没有点名的代码路径,本文也不会编一个来填这个空。它解释的是让 bug 得以发生的背景:这个补丁一次动的东西太多,随之而来的新 bug 也很多。声音池化是最后一天加的、未经测试的改动,带来了很多负面影响,后来通过更新禁用,看起来修好了大多数人遇到的问题。那是声音问题,不是存档问题,把两者混在一起,就是复述时制造的第二个 bug。

Rust 胶囊图:同样的标志与卫星天线剪影,更宽的裁切。Steam 商店官方图。

为什么开发分支上没人发现它

复盘对测试毫不含糊:当时没有内部 QA 团队。团队依赖玩家去玩开发分支,但这次更新的大多数问题在开发分支上本来就能看到,却没人去玩——正因为那些 bug。内部错误上报还不区分开发分支和主分支,开发分支上报的错误被主分支日常错误淹没了。测试链路不是在一个地方断的,而是三处全断:没人专职测试、没人玩测试分支、上报分不清测试错误和正式错误。

星期四发补丁是故意的,不是手滑。复盘解释说,补丁放在星期四而不是星期五,是因为团队预料会有 bug,想留一天在周末前修掉。但它给出的教训恰恰打破了这个习惯:不要被补丁日绑住,没准备好的就推迟、顶住压力,东西要在开发分支上经过合理程度的测试再放出来,哪怕补丁从此不再规律。还有一条诚实边界:同一篇复盘提到内存占用报告似乎只在升到 Unity 5.2 之后才出现,并明确标注未经证实。那是内存方面的观察,不是倒塌的原因,本文也按这个口径处理。

能复用的部分,先说清楚:这是通用做法,不是 Facepunch 的修复方案

Facepunch 没有为这次事件公布过修复流程,所以本篇能复用的部分是流程,不是代码。把每次补丁都当成一次数据丢失演练。打补丁前先做快照,并且在非正式环境里真的恢复一次,确认快照可用。先给正式世界的副本升级,而不是直接升正式服务器。先推一台服务器,再推全部,指定一个人有权拍板回滚。面向玩家的公告在补丁日之前就写好,不要等到故障时再写。这些步骤都不归于 Facepunch,因为复盘里没有写。它们是事件教给人的东西,以教训的口径说,不以史实的口径说。

周一早上照着做

  • 补丁碰正式服务器之前,快照已做好,并且已在非正式环境里恢复过一次。

  • 先在正式世界的副本上测升级,而且要测跑了很久的旧世界,不只测全新安装。

  • 先推一台服务器做灰度,再全量推送,并指定有权拍板回滚的人。

  • 回滚已就绪:上一版本和补丁前快照都在手边,而不只是写在文档里。

  • 补丁日之前就告诉玩家:改什么、什么时候改、状态更新发在哪里。

  • 上报里把测试分支错误和正式错误分开,让测试分支的信号不会被淹没。