一种使用 /transfer 的轻量化子服方案
李华是一个生电服的玩家,他总是在想,要是服务器里面有创造实验室就好了。 小叶是一个喜欢 PvP 的玩家,他总是在想,要是服务器里面有一个能干脆利落开启决斗的地方就好了。 作为这个服务器的 OP,这些场景对你来说不陌生。如果把这两个问题抛在 Minecraft 服务器社区里,相信绝大多数的回答都是「开一个新的子服务器并且建立跨服群组」,但是,这真的值得吗? 显然,这不值得。如果只是为了这两样功能启动一个跨服群组,你将会面临以下问题: 额外的维护成本: 使用群组服则基本排除了面板服务器部署方案的可能性,并且一个没有适当配置过的群组服务器会引起诸多问题,例如:玩家使用 /server 跳过验证关卡,子服务器的端口意外的暴露在外网等等。 资源需求上升: 启动额外的子服 + 代理程序则意味着你需要更多的资源。Java 主流 GC 的策略通常都会为了速度而将堆所占的空间悉数预分配,这导致即使程序使用的内存并没有那么多也会造成较高的 RSS. **资源分配不灵活:**上一个问题并不能简单的通过减少堆的大小解决。就以创造实验室为例,平时服务器内的人并不多,但一旦到了演示/大型机器实验时,较小的堆空间将会给 GC 带来相当的压力,并且无法利用到分配到其他(类似情况的,比如 PvP 竞技场)子服的空闲资源。 …… 光是想到从单端变群组,大多数服主就已经汗流浃背了。那么,本文所述的基于 transfer 机制的方案是如何规避这些问题的呢,他与其他类似方案又有何优劣之分呢? 基于世界的子服划分方式 这个情境中使用群组方案,归根结底是为了做服务器区域之间的划分。而 Minecraft 自带的多世界机制就已经很好的解决了活动空间的划分问题:没有传送门的情况下,玩家并不能随意大小跨。 早在 2013 年,PerWorldPlugins 就已经实现了将插件的生效范围降级到世界层次。通过切割插件在整个服务器中的作用域,这些世界得以模拟「服务器的子服」,使用此插件的用户可以通过限定不同世界里启用的插件来模拟多服务器的效果。而在约 2020 年,Valorin 的 DuelTime / Dantiao (付费) 将这个概念进一步推进,完全实现了本文引入部分时提到的「干脆利落开启决斗的地方」的设想。 然而,这样实现引入了许多需要额外维护的状态:生存服的玩家不能将物品带到创造服,他们也不希望在 PvP 服丢掉自己一身的好装备。插件需要小心翼翼的维护好这些状态,在跨世界转移的时候将他们的背包数据暂存起来,甚至有必要储存到硬盘上以防 崩服/断电/插件自身异常 导致数据丢失(数据无价!)。 并且,除了物品数据,还有许多问题需要考虑,比如玩家身上的 scoreboard / team 数据,其他插件储存的玩家相关的状态数据都可能会导致数据切割不干净。甚至如果这些插件涉及到储存功能,例如类末影箱类插件,邮箱等,被滥用的后果不堪设想。 而本文所述的方案使用 transfer 特性解决这些问题。 Transfer 是什么 /transfer 命令 是一项在 1.20.5 才被加入的新特性。如果你不知道他,只需要看这条命令的语法就可略知一二: /transfer <hostname> <port> [players] ...