一位 Rust 服主在补丁日星期四给跑了很久的服务器打了补丁,再登录时,眼看着基地一座座塌了。Facepunch 在自己的复盘里承认了这个 bug,却从没公布过背后的机制。这种诚实本身就是教训。
快速信息
Rust,Facepunch Studios 的生存游戏,事发时还在抢先体验阶段。
来源:Facepunch Devblog 80,补丁日星期四翻车后的复盘文章。
Bug 本身:该补丁最初服务器版本里的存档 bug。跑了很久的服务器打上补丁后,大量建筑倒塌。
没有继续坏的部分:之后重启没有问题,但这不等于什么都没丢。
复盘没给出的部分:没有机制、没有影响数、没有恢复说法、没有具名作者、抓取到的文本里没有具体日期。
同补丁的另一个问题是声音池化,属于未经测试的最后一天改动,后来通过更新禁用。它不是存档 bug。
最后核实:2026年10月27日。
补丁日星期四,和一台跑了很久的服务器
Facepunch 在 Devblog 80 开头就直白地道歉:星期四的补丁坏了,团队沟通也不好。这就是整篇复盘的调子,细节之前先值得学这一点。作者写道,游戏当时还在 alpha 阶段,但这不是把什么都往主分支上扔的借口。最严重 bug 的触发条件很具体,复盘原话就是:如果你的服务器已经跑了一段时间,然后打上了这个补丁,大量建筑就会倒塌。它没说所有服务器、所有玩家或全新安装都会中招。它说之后的重启没有问题。把这句话读两遍,因为本文剩下的部分都绕着它转。
复盘从没解释过机制。里面没有存档格式变化、没有序列化不匹配、没有稳定性重算、没有点名的代码路径,本文也不会编一个来填这个空。它解释的是让 bug 得以发生的背景:这个补丁一次动的东西太多,随之而来的新 bug 也很多。声音池化是最后一天加的、未经测试的改动,带来了很多负面影响,后来通过更新禁用,看起来修好了大多数人遇到的问题。那是声音问题,不是存档问题,把两者混在一起,就是复述时制造的第二个 bug。
为什么开发分支上没人发现它
复盘对测试毫不含糊:当时没有内部 QA 团队。团队依赖玩家去玩开发分支,但这次更新的大多数问题在开发分支上本来就能看到,却没人去玩——正因为那些 bug。内部错误上报还不区分开发分支和主分支,开发分支上报的错误被主分支日常错误淹没了。测试链路不是在一个地方断的,而是三处全断:没人专职测试、没人玩测试分支、上报分不清测试错误和正式错误。
星期四发补丁是故意的,不是手滑。复盘解释说,补丁放在星期四而不是星期五,是因为团队预料会有 bug,想留一天在周末前修掉。但它给出的教训恰恰打破了这个习惯:不要被补丁日绑住,没准备好的就推迟、顶住压力,东西要在开发分支上经过合理程度的测试再放出来,哪怕补丁从此不再规律。还有一条诚实边界:同一篇复盘提到内存占用报告似乎只在升到 Unity 5.2 之后才出现,并明确标注未经证实。那是内存方面的观察,不是倒塌的原因,本文也按这个口径处理。
能复用的部分,先说清楚:这是通用做法,不是 Facepunch 的修复方案
Facepunch 没有为这次事件公布过修复流程,所以本篇能复用的部分是流程,不是代码。把每次补丁都当成一次数据丢失演练。打补丁前先做快照,并且在非正式环境里真的恢复一次,确认快照可用。先给正式世界的副本升级,而不是直接升正式服务器。先推一台服务器,再推全部,指定一个人有权拍板回滚。面向玩家的公告在补丁日之前就写好,不要等到故障时再写。这些步骤都不归于 Facepunch,因为复盘里没有写。它们是事件教给人的东西,以教训的口径说,不以史实的口径说。
周一早上照着做
补丁碰正式服务器之前,快照已做好,并且已在非正式环境里恢复过一次。
先在正式世界的副本上测升级,而且要测跑了很久的旧世界,不只测全新安装。
先推一台服务器做灰度,再全量推送,并指定有权拍板回滚的人。
回滚已就绪:上一版本和补丁前快照都在手边,而不只是写在文档里。
补丁日之前就告诉玩家:改什么、什么时候改、状态更新发在哪里。
上报里把测试分支错误和正式错误分开,让测试分支的信号不会被淹没。

