更好的自动保存

更好的自动保存

为Forge 1.20.1服务器的异步世界保存——将区块、实体和已保存数据的序列化移出主线程。消除自动保存造成的卡顿。

优化

BetterAutoSave

BetterAutoSave

让服务器自动保存不再卡顿 ~ 本模组部分代码由 Claude Opus 4.8 / Claude Fable 5 生成。如果遇到任何问题,请提交 issue

本模组解决什么问题

原版 Minecraft 服务器每 5 分钟自动保存一次。保存时,主线程必须序列化每个已修改的区块并将其写入磁盘——在此期间整个服务器都会冻结。在空载服务器上你可能注意不到,但在安装大量模组和多名玩家的服务器上,这种暂停通常为 200 毫秒到数秒不等,并且所有玩家会同时卡顿。

除了定期自动保存外,以下几种情况也会导致同样的卡顿:

  • 玩家传送,或大量区块被卸载(区块在离开内存前必须保存)
  • 保存时实体密集的区域(大型农场 / 刷怪塔)——逐个保存实体会增加额外的停顿
  • 村庄、袭击以及某些模组数据(如 MTR 的列车数据)写入磁盘——单个大文件可能导致 50-200 毫秒的停滞

BAS 将整个保存过程移到后台线程。主线程只执行一项必须同步进行的操作——拍摄待保存数据的快照。序列化和磁盘 I/O 都交由后台处理。卡顿基本消失。

需求

  • Minecraft 1.20.1
  • Forge 47.3.22 或更新版本(47.3 / 47.4 系列均可)
  • Java 17 或更新版本
  • 仅服务端安装,客户端无需安装

安装

将 shinoyuki_betterautosave-0.11.0.jar 放入服务器的 mods/ 文件夹并启动。首次启动后,配置文件将生成在:

config/Shinoyuki-Optimize/shinoyuki_betterautosave/common.toml

默认配置开箱即用;大多数服务器无需修改任何内容。

会丢失世界数据吗?

不会。BAS 的设计前提是:绝对不能比原版更不安全。

  • 关闭服务器时,它会等待所有待处理的保存写入磁盘后才允许服务器退出。
  • 关闭时的最终保存会走原版同步路径,与未安装 BAS 时完全一致。
  • BAS 绝不会“推迟保存”——区块一旦需要保存,立即进入后台处理。不会出现“几分钟未保存,崩溃导致全部丢失”的时间窗口(一些类似模组存在此问题,详见下方兼容性说明)。
  • 如果后台写入失败,它会自动重试;重试耗尽后,会回退到原版同步写入,而非假装成功。

工作原理(可选阅读)

原版保存卡顿是因为两个繁重任务都放在主线程上:将世界数据序列化为保存格式,以及将序列化后的数据写入磁盘。

BAS 让主线程只做快照——将区块当前的方块、光照、方块实体等复制到一个独立副本中。这一步很快,因为它只是复制,不进行格式转换。复制完成后,主线程立即返回运行游戏,同时后台线程对副本进行序列化和磁盘 I/O。

由于后台线程操作的是副本,它们绝不会干扰主线程;快照完成后主线程便放手,无需等待写入完成。区块、实体和已保存数据都经过此流水线处理。

当服务器负载较高时,BAS 会自动减速(当 TPS 低于阈值时,每 tick 的快照数减少),但在下一次自动保存周期临近时会强制全速运行,以防止积压。

配置

配置文件位于 config/Shinoyuki-Optimize/shinoyuki_betterautosave/common.toml。常用条目:

键 默认值 描述
general.enabled true 总开关;关闭则恢复原版行为,如同未安装
throttle.chunksPerTickBase 4 主线程每游戏 tick 最多快照的区块数
throttle.adaptiveEnabled true 服务器负载高时自动减速;建议保持开启
workers.chunkWorkerThreads 2 处理区块的后台线程数
workers.entityWorkerThreads 2 处理实体的后台线程数
workers.savedDataWorkerThreads 1 处理已保存数据的后台线程数;如果有重型数据模组(如 MTR)可设为 2
compat.eventCompatMode PARTIAL 兼容性等级,见下方说明

其余条目(重试次数、关闭超时、监控开关等)在配置文件中有注释说明。

兼容性等级:eventCompatMode

少数模组会监听“区块保存”事件。此开关控制 BAS 提供给它们的数据完整性:

  • PARTIAL(默认,推荐):性能最佳,99% 的模组无法察觉差异。
  • FULL:100% 与原版一致,性能降低一半。仅当某个模组因无法读取区块方块数据而报错时切换至此模式。
  • DISABLED:完全不派发该事件;最节省资源,前提是你确定没有模组监听此事件。

不确定时,请保持 PARTIAL。

游戏内命令(需要 OP 权限)

命令 效果
/betterautosave status 一行显示当前状态
/betterautosave metrics 一行指标摘要
/betterautosave debug 完整诊断信息:队列深度、各阶段耗时、计数器
/betterautosave flush 立即同步刷新所有待处理的保存到磁盘
/betterautosave drain-unload 在关闭前手动等待所有待处理区块落地
/betterautosave hottest-chunks [count] 列出保存最慢的区块(默认 10,最多 50),用于定位热点
/betterautosave force-async 强制对当前维度所有区块执行一次后台保存(诊断用途)

监控(v0.9,可选)

v0.9 添加了两个诊断工具,让你无需外部分析器即可查看保存性能。

hottest-chunks 命令列出按保存时间降序排列的最慢区块:

/betterautosave hottest-chunks 20

高耗时区块通常位于方块实体密集的区域——大型自动化农场、模组商店面板、复杂红石。一旦知道精确位置,可以直接进行优化。

Prometheus 指标端点(默认关闭)会在配置的端口上提供 /metrics 页面。接入 Grafana 后可获得长期保存性能趋势,比反复运行 /betterautosave debug 方便得多。在配置中启用:

[prometheus]
enabled = true
port = 9450

安全提示:端口默认监听 0.0.0.0。在公共服务器(云 / VPS)上,请使用防火墙限制端口 9450,或将 bindAddress 设置为 127.0.0.1 以仅允许本地连接。指标不包含玩家隐私信息,但会暴露服务器的活动模式。

模组冲突

  • Smooth Chunk Save:二选一。两者都修改了区块卸载保存路径。相比之下,BAS 不会延迟磁盘写入(无数据丢失窗口),不会取消原版定期自动保存,也不会吞掉异常。
  • C2ME-Forge:接管了与 BAS 相同的保存路径;同时安装意味着重复处理,请二选一。该模组已不再维护,因此实际中重叠情况应该很少。
  • Lithium 移植版(Radium / Canary)、Starlight Forge:兼容。
  • 其他也涉及区块保存的模组:它们有时可能导致 BAS 接管失败,此时 BAS 会自动回退到原版处理——数据安全不受影响,只是会损失部分性能收益。

完整兼容性矩阵请参见 ROADMAP(中文)。

出问题时的快速恢复

以下三种方式均可保持世界数据完整:

  1. 临时禁用:在配置中将 general.enabled 设为 false,重启或使用 /reload。模组仍然安装,但所有逻辑被跳过——完全原版。
  2. 完全卸载:将 jar 移出 mods/ 文件夹并重启。世界数据受原版保存保护;卸载不会丢失任何内容。
  3. 调优而非移除:如果你怀疑是性能设置问题,可以先调整 chunksPerTickBase(范围 1-64)或将 eventCompatMode 切换为 FULL——无需卸载。

构建 / 开发

./gradlew build         # 编译 + 运行测试
./gradlew runServer     # 启动开发服务器

技术深入分析、生态研究、完整兼容性矩阵及版本路线图请参见 ROADMAP.md(中文)。

许可证

请参阅 LICENSE 文件。