ITADN
PaperMC/Folia
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

Version Folia Build Status Discord



Paper 的分支,为专用服务器添加了区域化多线程支持。

概述

Folia 将附近已加载的区块分组,形成一个“独立区域”。 有关 Folia 如何分组附近区块的详细信息,请参阅 PaperMC 文档。 每个独立区域都有自己的 tick 循环,以标准的 Minecraft tick 速率(20TPS)运行。 这些 tick 循环在线程池中并行执行。不再存在主线程, 因为每个区域实际上都拥有自己的“主线程”来执行整个 tick 循环。

对于玩家分布广泛的服务器,Folia 将创建许多分布广泛的区域, 并在可配置大小的线程池中并行 tick 所有这些区域。因此,Folia 应该能很好地扩展此类服务器。

Folia 也是一个独立的项目,在可预见的未来不会合并到 Paper 中。

更详细但抽象的概述:项目概述

常见问题

哪些服务器类型可以从 Folia 中受益?

自然使玩家分散的服务器类型, 如空岛生存(skyblock)或 SMP,将从 Folia 中受益最多。服务器 也应该有相当数量的玩家。

Folia 在什么硬件上运行效果最佳?

理想情况下,至少 16 个 核心(不是线程)。

如何最佳配置 Folia?

首先,建议预生成世界,以大幅减少所需的区块系统工作线程数量。

以下是基于 Folia 发布前我们在测试服务器上进行的测试得出的_非常粗略_的估算, 该测试服务器的峰值玩家数约为 330 人。因此,这并不精确,需要进一步调整 - 请仅将其作为起点。

应考虑机器上可用的总核心数。然后,为以下部分分配线程:

  • netty IO:每 200-300 名玩家约 4 个
  • 区块系统 IO 线程:每 200-300 名玩家约 3 个
  • 区块系统工作线程(如果已预生成),每 200-300 名玩家约 2 个
  • 对于未预生成的区块系统工作线程,没有最佳猜测值,因为 在我们运行的测试服务器上,我们分配了 16 个线程,但在约 300 名玩家时区块生成仍然 很慢。
  • GC 设置:???? 但是,GC 设置_确实_会分配并发线程,你需要 确切知道有多少个。这通常通过 -XX:ConcGCThreads=n 标志实现。不要 将此标志与 -XX:ParallelGCThreads=n 混淆,因为并行 GC 线程仅在 应用程序被 GC 暂停时运行,因此不应将其考虑在内。

在所有这些分配之后,系统中剩余的核心直到 80% 分配(分配的总线程数 < 可用 CPU 的 80%)可以 分配给 tickthreads(在全局配置中,threaded-regions.threads)。

你不应该分配超过 80% 的核心,原因是 插件甚至服务器本身可能会使用额外的线程, 而这些线程是你无法配置甚至无法预测的。

此外,以上所有内容都是基于玩家数量的粗略猜测,但 线程分配很可能并非理想状态,你需要根据最终观察到的 线程使用情况对其进行调整。

插件兼容性

不再存在主线程。我预计 每一个 存在的插件 都需要进行 某种 程度的修改才能在 Folia 中运行。 此外,任何类型 的多线程都会引入 插件持有数据中可能的竞态条件——因此, 必然需要进行一些更改。

因此,请将你对兼容性的期望值设为 0。

API 计划

目前,有大量 API 依赖于主线程。 我预计基本上没有任何与 Paper 兼容的插件 能与 Folia 兼容。然而,有计划添加 API, 以使 Folia 插件能够与 Paper 兼容。

例如,Bukkit Scheduler。Bukkit Scheduler 本质上 依赖于单一的主线程。Folia 的 RegionScheduler 和 Folia 的 EntityScheduler 允许将任务调度到拥有某个位置或实体的 区域的“下一 tick”。这些可以在常规 Paper 上实现, 只是它们调度到主线程——在这两种情况下, 任务的执行将发生在“拥有”该 位置或实体的线程上。这一概念普遍适用,因为当前的 Paper (单线程)可以被视为一个巨大的“区域”,涵盖 所有世界中的所有区块。

目前尚未决定是将此 API 直接添加到 Paper 本身, 还是添加到 Paperlib。

新规则

首先,Folia 会导致许多插件失效。为了帮助用户弄清楚哪些 插件可用,只有被作者明确标记为支持 Folia 的插件才会被加载。通过在 插件的 plugin.yml 中放置 "folia-supported: true",插件作者 可以将其插件标记为兼容区域化多线程。

另一条重要规则是,区域以_并行_方式 tick,而不是 _并发_方式。它们不共享数据,也不期望共享数据, 共享数据_会_导致数据损坏。 在一个区域中运行的代码在任何情况下都 不能访问或修改另一个区域中的数据。仅仅 因为多线程在名称中,并不意味着一切都 现在是线程安全的。事实上,只有_少数_事物被 制作成线程安全以实现这一点。随着时间的推移,线程 上下文检查的数量只会增加,即使_这_会带来 性能损失——_没有人_会使用或开发一个 bug 满天飞的服务器平台,而防止和发现这些 bug 的唯一方法是让错误的访问在 错误访问的源头_硬性_失败。

这意味着 Folia 兼容的插件需要利用 RegionScheduler 和 EntityScheduler 等 API,以确保 它们的代码在正确的线程上下文中运行。

通常,可以安全地假设一个区域拥有来自事件源(即玩家破坏方块,可能访问该方块周围 8 个区块)附近大约 8 个区块的数据。但是,这并不保证——插件应利用即将推出的线程检查 API 以确保正确的行为。

线程安全的唯一保证来自于这样一个事实:单个区域拥有特定区块的数据——并且如果该区域正在 tick,则它对该数据拥有完全访问权限。这些数据具体是实体/区块/POI 数据,与任何插件数据完全无关。

常规的多线程规则适用于插件存储/访问其自身数据或另一个插件的数据——事件/命令等是并行调用的,因为区域是并行 tick 的(我们无法以同步方式调用它们,因为这会引发死锁问题并损害性能)。没有简单的解决方案,这完全取决于正在访问的数据。有时并发集合(如 ConcurrentHashMap)就足够了,而经常不加小心地使用并发集合只会掩盖线程问题,从而使调试变得几乎不可能。

当前 API 新增

为了正确理解 API 新增,请阅读 项目概览

  • RegionScheduler、AsyncScheduler、GlobalRegionScheduler 和 EntityScheduler, 作为 BukkitScheduler 的替代方案。 实体调度器通过 Entity#getScheduler 获取,其余调度器可从 Bukkit/Server 类中获取。
  • Bukkit#isOwnedByCurrentRegion 用于测试当前正在 tick 的区域 是否拥有该位置/实体

API 的线程上下文

为了正确理解 API 的添加,请阅读 项目概览

一般经验法则:

  1. 针对实体/玩家的命令在拥有该实体/玩家的区域上调用。 控制台命令在全局区域上执行。

  2. 涉及单个实体的事件(例如玩家破坏/放置方块) 在拥有该实体的区域上调用。涉及对实体执行操作的事件 (例如实体受到伤害)在拥有目标实体的区域上调用。

  3. 事件的 async 修饰符已弃用 - 所有 从区域或全局区域触发的事件均被视为_同步_, 尽管不再存在主线程。

当前已损坏的 API

  • 大多数与传送门 / 玩家重生 / 某些 玩家登录 API 交互的 API 已损坏。
  • 所有记分板 API 均被视为已损坏(这是全局状态, 我尚未想出如何正确实现)
  • 世界加载/卸载
  • Entity#teleport。这在任何情况下都不会恢复, 请使用 teleportAsync
  • 可能还有更多

计划中的 API 添加

  • 真正的异步事件。这将允许事件的结果在稍后、在不同的线程上下文中完成。实现某些功能(如出生点选择)需要此功能,因为访问区域外的区块数据时需要异步加载区块。
  • 世界加载/卸载
  • 更多内容将在此处添加

计划中的 API 更改

  • 全面采用极其严格的线程检查。这绝对必要,以防止插件开发者发布可能以完全_无法诊断_的方式随机破坏服务器随机部分的代码。
  • 更多内容将在此处添加

Maven 信息

  • Maven 仓库(用于 folia-api):
<repository>
    <id>papermc</id>
    <url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
  • 构件信息:
<dependency>
    <groupId>dev.folia</groupId>
    <artifactId>folia-api</artifactId>
    <version>[26.1.2.build,)</version>
    <scope>provided</scope>
</dependency>

许可证

PATCHES-LICENSE 文件描述了 api 和 server 补丁的许可证, 位于 ./patches 及其子目录中,除非另有说明。

该分支基于 PaperMC 的分支示例,见此处。 因此,它包含本项目中的修改,请参阅仓库以获取已修改文件的许可证信息。