仓库链接
BorderRegion/Irminsul: 更适合Minecraft服务器场景下的Ledger数据库
如果这个项目有帮助到您,可以点一个⭐嘛,非常感谢!(´∀`)
Irminsul-银白古树
Irminsul 是 Ledger 的一个实验分支。它保留 Ledger 原本的记录、查询和回滚能力,额外加入了 一个同名的本地数据库后端。它牺牲了一些通用数据库能力,换取更低的写入开销、更小的数据体积,以及更可控的内存和回滚压力。
下面的数据来自同一台远程测试机,在服务器进行大量的填充、TNT爆炸等更新以测试数据库的性能。不同硬件、JVM 参数、模组包、在线人数和区块加载情况,
都会让结果变化。
| 测试项 | Irminsul | MySQL | 差异 |
|---|---|---|---|
| 写入高峰后的队列 drain | 约 1.0 s | 约 35.1 s | 约 30 倍更快 |
| 数据占用 | 约 20.0 MB | 约 68.7 MB | 约少 70% |
| 回滚范围测试 | 约 1.0 s | 约 2.0 s | 约 2 倍更快 |
主要改动
这次主要改动集中在数据库、写入队列、查询和回滚这几块。简单说,就是尽量让 Ledger 在高写入和大范围操作的时候,不要被数据库拖住。
首先是新增了 Irminsul 本地数据库后端,可以在 config/ledger.toml 里通过下面的配置启用:
[database]
engine = "irminsul"
原来的 SQL/JDBC 后端没有删掉,MySQL、MariaDB 这些还是可以继续使用。项目里把数据库访问抽成了 LedgerStore,这样 SQL 和 Irminsul 可以走同一套上层逻辑,不需要把 Ledger 原来的记录、查询、inspect、rollback、restore 功能全部重写一遍。
Irminsul 使用的是本地 append-only 文件存储,默认数据目录在世界目录下面的 world/ledger-irminsul。这种方式不追求通用数据库那样完整的管理能力,而是更偏向 Minecraft 服务器这种大量追加写入、按时间和位置查询、需要快速处理相似记录的场景。
解决了什么问题
第一个问题是写入高峰之后队列 drain 很慢。比如大面积填充、爆炸、红石机器、刷物品、区块大量更新时,Ledger 会短时间产生很多记录。如果这些记录全部压给 MySQL,服务器可能会等数据库慢慢处理。Irminsul 通过本地追加写入降低了这部分开销。
第二个问题是数据体积。Ledger 记录里有很多重复内容,比如 action 类型、世界 id、来源、玩家名、方块状态、注册 id 等。Irminsul 对这些重复字符串做了字典编码,减少重复内容占用的空间。测试里数据占用从 MySQL 的约 68.7 MB 降到 Irminsul 的约 20.0 MB。
第三个问题是历史记录越来越多之后,内存和查询压力不好控制。Irminsul 把近期数据作为热数据保留索引,旧数据留在磁盘上按需扫描。这样不是把所有历史记录都硬塞进内存,而是让内存占用更可控。
第四个问题是极端写入时内存队列可能满掉。现在加入了磁盘溢写队列,当 maxQueueSize 达到上限之后,多出来的记录会进入 ledger-queue,之后再按批回放。一次极端测试中,强制把 maxQueueSize 压到 256,溢写到磁盘的记录为 260596 条,丢弃记录为 0。
第五个问题是大范围 rollback / restore 容易卡服务器。Irminsul 这边加入了每 tick 时间预算、每 tick 最大处理数量、冲突跳过、同位置去重和回滚日志抑制。它不是单纯追求最快把所有动作执行完,而是尽量把压力摊到多个 tick 里,避免回滚时把在线玩家一起卡住。
具体做了哪些优化
- 新增 Irminsul 后端,通过
engine = "irminsul"启用。 - 保留原 SQL/JDBC 后端,不影响继续使用 MySQL、MariaDB 等数据库。
- 抽象出
LedgerStore,让 SQL 和 Irminsul 共用上层逻辑。 - 使用本地 append-only 文件存储,减少高频写入时的数据库开销。
- 对 action、世界、来源、玩家、方块状态、注册 id 等做字典编码。
- 完整保留注册名,不只支持
minecraft:*,也支持模组里的modid:*。 - 近期数据保留热索引,旧数据留在磁盘上做冷扫描。
- 索引缓存可以根据 JVM heap 和主机内存估算,也可以手动限制。
- 写入队列达到上限后进入磁盘溢写队列,避免内存队列无限增长。
- 冷数据查询、分页、计数和回滚规划改成更偏流式的处理方式。
- rollback / restore 加入节流、冲突跳过、同位置去重和日志抑制。
ledger status和关服 drain 会把磁盘溢写队列也统计进去。
使用建议
这个后端比较适合单个 Minecraft 服务器、本地 SSD、Ledger 写入量很大、并且已经明显感觉 MySQL 查询或者回滚变慢的情况。如果有测试服、镜像服或者灰度服,可以先拿来跑一段时间观察。
不太建议没有备份的正式主服直接使用。尤其是模组包很复杂、在线人数较多、没有实际恢复过备份、不能接受停服排查的服务器,最好先不要直接放进生产环境。
如果要测试,建议重点观察这些东西:写入高峰后的队列 drain、冷数据搜索速度、大范围 rollback / restore、关服 drain、JVM 内存、磁盘增长、tick 时间,以及异常关服之后能不能正常恢复。
常用配置
[database]
engine = "irminsul"
batchSize = 1000
batchDelay = 10
maxQueueSize = 250000
spillBatchSize = 5000
rollbackTickBudgetMillis = 5
rollbackMaxActionsPerTick = 2000
rollbackSkipConflicts = true
irminsulSegmentSizeMiB = 128
irminsulFsyncOnBatch = false
irminsulHotActionLimit = 2000000
irminsulIndexCacheMiB = -1
其中 maxQueueSize 是内存写入队列上限,超过后进入磁盘溢写队列;spillBatchSize 控制每批从磁盘溢写队列回放多少记录;rollbackTickBudgetMillis 和 rollbackMaxActionsPerTick 用来控制每 tick 的回滚压力;irminsulHotActionLimit 是热索引驻留上限,不是数据保留天数。
最后说明
Irminsul 是针对 Minecraft 服务器场景做的一个本地性能优化后端,用更低的写入开销、更小的数据体积和更可控的回滚压力,换取一部分通用数据库能力。
目前从测试结果看,它在高写入、冷数据查询和回滚这些场景里都有比较明显的改善。但是不同服务器的硬件、JVM 参数、模组包、在线人数和玩法都会影响结果,所以这些数据只能当作参考,不应该直接当成所有环境里的保证。
重要提醒:Irminsul 目前仍然是实验版本,还没有经过充分、长期、真实生产环境的测试。
使用之前强烈建议先在测试服、镜像服或灰度服中验证备份恢复、异常关服恢复、大范围查询、rollback、restore、关服 drain、JVM 内存、磁盘增长和 tick 时间,不建议在没有备份和回退方案的正式主服中直接使用。
