本页内容
游戏服务器是一种特殊的工作负载。它的瓶颈很少出在 CPU 总量、内存或带宽上,而在于单个线程完成每个模拟 tick 的速度。本指南将说明这对硬件意味着什么、如何估算一台机器能容纳多少个游戏服务器,以及如何在 Linux 上运行它们,并做好合理的防护和备份。
Tick 时间预算
权威服务器(authoritative server)以固定频率推进游戏世界。每个 tick 依次处理玩家输入、物理、AI 和游戏规则,再把状态发送给客户端。每个 tick 可用的时间很容易算出:
| Tick 率 | 每个 tick 的时长 |
|---|---|
| 20 Hz(Minecraft Java 版) | 50 ms |
| 30 Hz | 33.3 ms |
| 64 Hz | 15.6 ms |
| 128 Hz | 7.8 ms |
一旦某个 tick 的耗时超出预算,服务器就会落后,每位玩家都能感觉到:角色被拉回、命中判定延迟、挖掉的方块又重新出现。在许多引擎中,大部分模拟都跑在一个主线程上,这时增加核心数也无济于事。
为什么主频和缓存至关重要
单线程性能等于每时钟周期指令数(IPC)乘以频率。FlexDedi 的所有服务器都采用 Zen 5 核心,因此差异来自频率和缓存:Core 16 的加速频率可达 5.4 GHz,Core 16X 可达 5.7 GHz,而 EPYC 9005 系列服务器为 4.4 至 4.5 GHz。基础频率同样重要,因为一台满载的游戏主机会让所有核心都处于忙碌状态:Core 16X 的基础频率为 4.3 GHz,Core 16 为 3.0 GHz。
缓存之所以重要,是因为游戏状态的内存访问毫无规律。实体、区块、物理刚体和寻路数据分散在内存各处,而一次 L3 缓存命中比访问一次 DRAM 大约快一个数量级。工作集能装进缓存,主线程就能一直在计算,而不是在等待数据。
Core 16X 的 3D V-Cache
Core 16X 搭载的 EPYC 4585PX 在处理器上额外堆叠了 L3 缓存,总容量达 128 MB,而 Core 16 所用的 EPYC 4545P 为 64 MB。3D V-Cache 正是为大型、不规则的工作集而设计的,游戏模拟就是其中之一。它能带来多大提升,取决于具体游戏、地图和玩家数量,因此请用你自己的游戏实测,不要想当然。
这些缓存并不是平均分配的。16 核 Zen 5 处理器由两颗 8 核芯片(CCD)组成,每颗各有 32 MB L3 缓存,额外的 64 MB 只位于其中一颗上:一个 CCD 有 96 MB,另一个只有 32 MB。用以下命令找出哪些逻辑 CPU 共享大容量缓存:
for d in /sys/devices/system/cpu/cpu*/cache/index3; do
echo "$(cat "$d/size") $(cat "$d/shared_cpu_list")"
done | sort -u正常会输出两行,例如 98304K 0-7,16-23 和 32768K 8-15,24-31;你服务器上的编号可能不同。把负载最重的游戏服务器绑定到大缓存 CPU 上。有些游戏更看重频率而不是缓存,所以在最终定下方案前,先在两组 CPU 上用同一张地图分别跑一遍基准测试。
SMT 与调频策略
为每个游戏服务器的主线程分配一个独占的物理核心;同一核心上的另一个 SMT 线程可以跑辅助线程。在裸金属上,你还能控制调频策略,而虚拟机从不开放这一点。查看当前的调频驱动和 governor,并在对延迟敏感的主机上使用 performance:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor该设置在重启后会失效,可以写一个简单的 systemd unit 来应用它,使其持久生效。
一台机器能跑多少个游戏服务器
没有哪个通用数字是靠得住的。它取决于游戏本身、模组、地图大小、玩家数量和 tick 率。先测出单个实例在高峰时的资源占用,再做计算:
- 以贴近真实的玩家数量运行一个服务器实例,记录主线程 CPU 占用、常驻内存(RSS)、存档时的磁盘写入以及网络吞吐量。
- 按下表逐项计算每种限制,取其中最小的结果。
| 限制因素 | 估算方法 |
|---|---|
| CPU | (物理核心数 − 为操作系统、面板、备份预留的核心数)÷ 每个实例占用的核心数 |
| 内存 | (内存总量 − 为操作系统和页缓存预留的余量)÷ 每个实例的峰值 RSS |
| 网络 | (端口速率 × 安全系数)÷(玩家数 × 每位玩家的带宽) |
| 磁盘 | 能同时进行而不拖慢 tick 的存档数量 |
下面的示例使用假设数据,并非实测值:每个实例的主线程需要一个物理核心,内存峰值为 8 GB。在 Core 16X 上预留 2 个核心和 32 GB 内存,按 CPU 计算可运行 14 个实例,按内存计算为 (192 − 32) ÷ 8 = 20 个。瓶颈在 CPU,因此按 14 个左右规划,再在真实负载下验证。
以下几条规律适用于大多数游戏:
- 持久化沙盒世界(生存、建造和殖民地经营类游戏)的内存占用和存档体积会随运行时间不断增长,因此每隔几周要重新测量一次。
- 对局制服务器生命周期短,内存占用通常也不高,因此上限由 CPU 决定。
- Minecraft Java 版在一个主线程上处理世界 tick。Paper 等服务端软件可以降低每个 tick 的开销,用
/mspt或 spark 性能分析器可以看出距离 50 ms 预算还有多远。给 JVM 设置固定大小的堆(-Xms等于-Xmx),大小按服务器的实际用量设定,而不是把所有内存都分给它。 - 网络很少成为瓶颈,因为与 10 Gbps 端口相比,每位玩家的流量很小。更需要关注的是数据包速率和攻击流量。
DDoS 防护
游戏服务器是 DDoS 攻击的常见目标。FlexDedi 的每个 IP 都自带始终开启的 DDoS 防护,攻击流量会被自动过滤,无需你手动开启任何功能。不过,主机侧的安全基本功依然不可少:
- 只开放每个游戏需要的端口,并指定正确的协议,例如
ufw allow 25565/tcp或ufw allow 27015/udp。 - 不要把 RCON、查询(query)和管理端口暴露在公网上,将它们绑定到
127.0.0.1或内网地址。 - Web 面板应放在 VPN 或 IP 白名单之后,插件或面板使用的数据库绝不能对外暴露。
根据玩家分布选择机房
距离决定了延迟的下限。光在光纤中每毫秒大约传播 200 km,因此路径每增加 1,000 km,往返时延至少增加 10 ms。粗略估算,达拉斯到洛杉矶和纽约的距离都约为 2,000 至 2,200 km,到东西两岸的往返时延物理下限约为 20 至 22 ms,路由还会在此基础上进一步增加。
选择离大多数玩家最近的机房:北美可选纽约、阿什本、达拉斯或洛杉矶;欧洲可选阿姆斯特丹、法兰克福或伦敦;亚太可选新加坡、东京或悉尼。Core 16 和 Core 16X 在全部十个机房均有供应。下单前,可以通过 Looking Glass 向玩家所在的网络运行 ping 和 traceroute。
在 Linux 上用 systemd 部署
先参照新 Linux 服务器安全加固等指南建立安全基线。然后让每个游戏服务器以非特权用户身份、在各自的目录中、由 systemd 托管运行。同一款游戏的多个实例,用一个模板 unit 即可全部覆盖:
# /etc/systemd/system/minecraft@.service
[Unit]
Description=Minecraft server %i
After=network-online.target
Wants=network-online.target
[Service]
User=minecraft
WorkingDirectory=/srv/minecraft/%i
ExecStart=/usr/bin/java -Xms8G -Xmx8G -XX:+UseG1GC -jar server.jar --nogui
Restart=on-failure
RestartSec=10
SuccessExitStatus=0 143
TimeoutStopSec=90
CPUAffinity=0-7 16-23
Nice=-5
NoNewPrivileges=true
ProtectSystem=full
PrivateTmp=true
[Install]
WantedBy=multi-user.targetsudo useradd --system --create-home --home-dir /srv/minecraft --shell /usr/sbin/nologin minecraft
sudo systemctl daemon-reload
sudo systemctl enable --now minecraft@survival minecraft@creative
journalctl -u minecraft@survival -f每个实例位于 /srv/minecraft/NAME。停止时,systemd 发送 SIGTERM;服务器保存世界后,JVM 以状态码 143 退出,SuccessExitStatus 会将其视为正常退出。CPUAffinity 把实例绑定到前面找到的大缓存 CPU 上。如果要把较轻的实例移到另一组 CPU,运行 sudo systemctl edit minecraft@creative,先添加一行空的 CPUAffinity=,再写入新的 CPU 列表,否则该设置会与模板中的值合并。systemd 不提供交互式控制台,因此请通过 RCON 管理服务器,例如使用 mcrcon 客户端。
LinuxGSM 与管理面板
LinuxGSM
LinuxGSM 是一款命令行管理工具,支持 100 多种游戏服务器。它负责安装服务器、在 tmux 中运行,并提供监控、更新和备份功能。每款游戏使用各自独立的用户:
sudo adduser vhserver
su - vhserver
curl -Lo linuxgsm.sh https://linuxgsm.sh && chmod +x linuxgsm.sh && bash linuxgsm.sh vhserver
./vhserver install
./vhserver start
./vhserver detailsvhserver 对应 Valheim(英灵神殿);每款受支持的游戏都有自己的简称。该项目建议为 monitor(自动重启崩溃的服务器)和 update 设置 cron 定时任务:
*/5 * * * * /home/vhserver/vhserver monitor > /dev/null 2>&1
*/30 * * * * /home/vhserver/vhserver update > /dev/null 2>&1Pterodactyl 类面板
Pterodactyl 一类的面板(包括其分支 Pelican)把工作拆成两部分:一个带数据库的 Web 面板,用于创建服务器和用户;以及运行在每台游戏主机上的守护进程,它把每个游戏服务器放在独立的容器中运行,并施加 CPU、内存和磁盘限制。这类面板适合服务器数量多或管理人员多的场景。无论选用哪一款,都应遵循以下几条原则:
- 把面板部署在一台单独的小型服务器或虚拟机上,通过内网访问各台游戏主机。
- 为每个服务器设置 CPU 限制;如果面板支持,还应绑定线程,让负载重的服务器落在大缓存 CPU 上。
- 容器通过 Docker 发布端口,会绕过 UFW,因此要通过面板的端口分配和 Docker 的
DOCKER-USER链来控制暴露面。
备份
游戏世界是无法替代的部分。要定期备份、在本机之外保留副本,并测试恢复:
- 复制期间暂停存档,以保证文件一致。对于 Minecraft,先通过 RCON 发送
save-off和save-all flush,复制世界文件后再发送save-on。LinuxGSM 的./vhserver backup会生成自己的归档文件。 - 用 restic 或 rsync 把副本传到另一台服务器。同一机房的存储服务器可以通过免费内网接收备份;放在第二个机房则能防范机房级事故;而不限流量意味着异地备份不会产生任何传输费用。
- 保留多个历史版本,因为世界文件损坏可能好几天都没人发现。
在 FlexDedi 上运行
大多数游戏托管场景,建议从 Core 16X($399/月)起步:EPYC 4585PX 处理器,带 3D V-Cache,基础频率 4.3 GHz,加速频率 5.7 GHz,192 GB DDR5 ECC 内存,以及 2 × 3.84 TB NVMe。Core 16($299/月)适合较轻量的游戏和测试服务器。两者均配备 10 Gbps 端口,不限流量,提供始终开启的 DDoS 防护,全部 10 个机房均有供应,通常 15 分钟内即可交付。
如果你要同时托管大量小型游戏服务器以及面板和数据库,Pro 32($749/月)以单核速度换来 32 个核心和 384 GB 内存。更多信息请参阅游戏服务器托管。