[博客翻译]Copyover MUD服务器的工作原理


原文地址:http://jackkelly.name/blog/archives/2025/02/06/how_copyover_mud_servers_worked/


MUD服务器的“Copyover”机制是如何工作的?

当我还是个孩子的时候,我花了很多时间玩MUD(Multi-User Dungeons,多人地牢游戏)。这是现代MMORPG的前身,一种纯文字的多人在线游戏,玩家通常通过Telnet协议连接到服务器。这种游戏在高中时特别有趣:它轻量级、无需客户端状态,可以让你从任何实验室里的电脑登录。即便是在那个年代,Windows系统自带了Telnet客户端,这种协议也足够轻便,能够运行在我学校里缓慢的电脑和有限的网络连接上。此外,没有华丽的图形意味着如果你遇到路过的老师或图书管理员,可以迅速隐藏窗口而不被发现。

后来,我发现自己对构建和修改MUD的兴趣比玩游戏更大了。在那个时候,MUD的建设者和管理员(称为“巫师”)往往是从玩家中招募而来的,并且许多MUD允许这些建设者通过游戏内命令直接编辑世界内容。这在当时非常酷——即使使用笨拙的基于行的文本编辑器(类似于ed),从无到有创建空白房间、为它们编写生动的描述,以及添加物品和NPC(称为“mobs”,即移动对象),都让人感到无比神奇。我和一些朋友报名参加了某个“建造学院”的MUD,在那里每个人都有一片区域可以自由折腾。我们尝试打造自己的游戏场景,但大多数项目都没能持续太久,所有的一切都随着时间消失了。

不过,在别人的MUD上拥有建造权限只能做到这么多。如果你想真正改变游戏规则,你需要学习编程。当时的大多数MUD都是用真正的编程语言(比如C)编写的。我们设法弄到了一份Visual C++ 6和CircleMUD的源代码,并开始进行实验。然而,开发周期相当令人沮丧——每次修改后,你都需要重新编译服务器,关闭它(切断所有玩家的连接),然后再重启并等待大家重新登录。

有些MUD使用了一种很酷的技巧来避免这个问题,叫做“copyover”(热启动)。这是一个让服务器在保留进程ID(PID)和开放连接的同时更新自身的巧妙方法。这在当时看起来像是魔法:你重新编译服务器,发送正确的命令,一切会暂停几秒钟,然后(如果幸运的话)新的代码就会启动并继续运行。虽然这个技巧很简单,但我没找到详细的文档,所以想趁着还记得把它写下来。

我最熟悉的copyover方法是这样工作的:

  1. 触发copyover命令:由MUD管理员发起。
  2. 创建管道:服务器调用pipe(2)创建一个“管道”。新版本的服务器将从这个管道读取数据,旧版本则向它写入数据。
  3. 复制自身:服务器调用fork(2)生成一个自身副本,从而产生一个父进程和一个子进程,二者共享相同的状态。
  4. 子进程保存状态子进程关闭管道的读取端,将自己的游戏状态写入管道,然后退出。
  5. 父进程替换自身:与此同时,父进程关闭管道的写入端,并调用exec(3)函数将其替换为新的二进制文件。在这个exec调用中通常还包括特定的“copyover”标志和管道读取端的文件描述符。请注意,文件描述符(包括开放的套接字)会在exec()调用中保持打开状态。
  6. 加载新状态:与此同时,父进程(现在运行的是新代码)通过管道读取游戏状态,然后关闭管道。
  7. 清理子进程父进程调用wait(2)以清除僵尸状态的子进程

此时,我们的目标已经实现:服务器以原有的PID运行新代码,并保留了旧的状态。这个方案的最大弱点是,如果新服务器无法成功启动,你就无法终止copyover过程,并且会丢失所有的游戏状态。如果我们放弃保留恒定的PID,我可以想象更复杂和更可靠的方案。例如,可以使用更高级的通信机制(如Unix域套接字)代替管道,让新服务器报告自己已准备好接管;或者可以将网络连接处理与游戏逻辑分离,通过SCM_RIGHTS传递套接字,利用memfd存储copyover状态,甚至通过systemd的文件描述符存储功能在进程替换期间保留这些资源。

简单的copyover服务器使用了众所周知的Unix原语——管道、fork(2)exec(3)中的文件描述符持久化——但其实稍微聪明一点就能证明,Unix的充分运用几乎是“难以与魔法区分”的。其他例子包括Factorio使用fork(2)在macOS和GNU/Linux上实现异步保存,以及Cloudflare使用SCM_RIGHTS将TLS 1.3连接传递给单独的进程。很多时候,看似神奇的功能并非源于Unix本身,而是因为很多原语如今已经被跨语言运行时或平台抽象库所隐藏,甚至完全被人遗忘。我最初只是打算记录下传统的状态ful服务器复制方式,但在探索过程中发现了更多值得研究的内容。还有哪些东西是我遗漏的呢?Stevens的《UNIX环境高级编程》是否仍然是这一领域的权威参考书?


阅读全文