Minecraft 大型多人游戏的未来?—— MultiPaper

Minecraft 大型多人游戏的未来?—— MultiPaper

从今年早些时候开始关注 MultiPaper,到现在 MultiPaper 的完成度终于值得让我写一篇文章赞美一下了(好欸! GitHub <

从今年早些时候开始关注 MultiPaper,到现在 MultiPaper 的完成度终于值得让我写一篇文章赞美一下了(好欸!

MultiPaper 诞生的背景

TPS 的概念

每个架设过 Minecraft 的服主都多多少少要和 TPS (ticks per second) 打交道,MC 这个游戏的游戏世界所有内容都基于一个循环进行计算,每一个循环称为 1 个tick,每秒循环 20 次,如果这一秒循环次数不够 20 次,则会出现卡顿的情况,服务器会在下一秒尝试多循环补偿 tick 丢失。

由于每个部分(方块、生物、AI等等)他们之间都互相关联引用,这也导致了所有计算都必须在同一个线程上进行,也就是 MC 常被人吐槽是个单线程游戏的原因。

游戏的优化

说实话,Minecraft 游戏的优化可以说是相当糟糕,仅限于 <10 人能玩的程度。

随着版本的更新,越来越多的内容被加入到游戏中,Server Thread(负责逻辑运算的线程,下称主线程)越来越不堪重负,以至于在最近几个版本,不使用第三方服务端的情况下,几乎无法多人游玩的情况下达到 20 TPS 的程度。

组建一个像是 CDN 一样的 Minecraft 网络

在 MultiPaper 诞生之前,大部分服务器都通过诸如 BungeeCord 或者 Velocity 等的代理软件,通过区域切割、架设子服务器等手段,将玩家分散到不同的 MC 服务器实例中,抑或是对部分内容进行异步计算以减轻单个服务器实例的负载压力。

然而,这种手段割裂了玩家的游戏体验 —— 每个实例都单独管理和计算,玩家几乎不可能做到在同一个地图内互相交互 —— 而异步计算的内容有限,主线程仍然成为了性能瓶颈。

水平拓展

垂直拓展已无空间,那么为什么不水平拓展呢?

Minecraft 的主线程设计导致水平拓展要考虑大量的互相通信和数据同步问题,在此之前,不要说多实例,甚至多线程的服务端都寥寥无几。

而 MultiPaper 正是为此而生的。

主从设计

MultiPaper 采用了常见的主从设计,如果不熟悉的话 —— 类似 MySQL 的 Master & Slave 之间的关系。

官方 Github 仓库的工作原理演示

Master 主管调度和数据存储与同步,可以单独运行或者作为 BungeeCord/Velocity 插件运行。

各个 Slave 各持有一部分区块的 “控制权”,每个 Slave 之间通过 Socket 方式相互通信。

当需要跨服务器读取数据时,Slave 会根据情况选择向 Master 请求目标区块的控制权,或者进行 P2P 通信;而更改也会通知到其他所有需要更新的服务器中。

区块控制权

区块控制权是 MultiPaper 的核心 —— 它决定了一个区块是被哪个 Slave 负责 tick 和管理。

周围的区块所有权分布情况 - 蓝色:当前玩家所在的 Slave;红色:非玩家服务器

对于复杂操作例如 TNT、双箱、红石等(或者频繁操作),Slave 会向 Master 申请目标区块的控制权。

一旦成功,该区块的 tick 和管理权限将由原 Slave 转交给发起请求的 Slave,也就完成了 “区块控制权的转移” 同时也是 “负载的转移”,这样就完成了负载均衡的目标 —— 即将负载平均到多个实例中。

除了上述提到的情况会请求控制权外,如果某个 Slave 意外下线,另一个 Slave 也会按需要将其接管。

第一次打开是 P2P 了 slave-2,第二次打开是区块控制权抢夺

实例间的 P2P 通信

除了控制权争夺外,还有另一种通信方式:Peer Connection。

在控制权争夺失败,或者少量交互的情况下,MultiPaper 会使用一种 P2P 的方式互相通信。

常见的,部分情况下 AI 寻路、PVE等就是 P2P 形式进行的。

当 request 返回 false 时,就将使用 P2P 的方式交互,为 true 时则移交控制权

缺点也非常明显,P2P的形式会出现网络通信不可避免的延迟问题。

不过好在除了抛掷物以外,其他的延迟基本不可感知。

红石 P2P 演示

体验衔接

MultiPaper 跨服务器几乎是完全不可感知的,不论是生物寻路、跨服务器大箱子打开、漏斗、火焰蔓延、刷怪笼、原版命令、Allay 寻找物品、村民跨服获取职业和操作方块,一切都是无缝的体验。

狐狸攻击鸡跨服AI演示
村民跨服寻路和职业获取演示

不过 P2P 的抛掷物会出现一些延迟和不同步问题,大概以后会解决:

蓝色(slave-3)为录屏玩家所在服务器,只有该玩家一人;红色部分是其他服务器,图中所有其他人的所有操作都是 P2P 状态之下传输的

MultiPaper 是大型 Minecraft 网络的 【目前来说】的最佳解决方案

正如官方 Github 所讲,MultiPaper 构建的 Slave 集群可以轻松托管超过 1000 个玩家(当然,CPU核心数 和内存得管够)。

官方的 Master 内置的代理可以把玩家分散到负载较低的服务器中达到负载均衡的效果。

(至少是一个Slave TPS崩塌了不会影响其他 Slave)

对 MultiPaper 进行 LambdaAttack 压力测试,共有 4 个 Slave,双视距为 10 chunks,不修改任何配置和打开优化开关,每个玩家进入服务器时都随机传送,测试玩家人数 1000 人,效果如下。

同一个 MultiPaper 网络下 1000 人
每个玩家加入服务器后都被随机传送到不同位置
4 个 Slave 服务器的性能状态,已经都被推上了极限
系统负载(任务管理器)

关于有人问到的 “玩家怎么无缝跨 Slave 的,是传送吗?” —— 玩家永远不会更改自己的 Slave 服务器,进去哪个就一直是哪个,都是跨服通信而已。

为什么说 MultiPaper 是未来

以 Paper 为首的社区目前仍然在积极的提升单实例的性能,目前已经被引入的异步区块生成、异步区块加载和IO、AI控制、重写的照明引擎等等已经对比 Vanilla 服务端有了相当大的提升。而且也在致力于引入新的性能补丁——例如区块系统重写的补丁。

@Namiu 录制的新的区块系统的性能对比测试(已过时,现在效果应该更好了)

然而,就像 CPU 的制程提升是有限的一样,无论在单个实例上做出多少优化,最终都会被软件或是硬件的性能瓶颈所限制。

对于大型 Minecraft 服务器来说,这种水平拓展的能力仍然是必要的。

来自 MultiPaper 官方的演示视频

国内可能无法访问↑

引用文献

Comment