惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

P
Privacy & Cybersecurity Law Blog
Engineering at Meta
Engineering at Meta
Forbes - Security
Forbes - Security
MongoDB | Blog
MongoDB | Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
A
About on SuperTechFans
量子位
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
雷峰网
雷峰网
腾讯CDC
P
Proofpoint News Feed
S
Schneier on Security
S
Secure Thoughts
V
Visual Studio Blog
Help Net Security
Help Net Security
The Hacker News
The Hacker News
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Privacy International News Feed
SecWiki News
SecWiki News
S
SegmentFault 最新的问题
T
Threatpost
小众软件
小众软件
MyScale Blog
MyScale Blog
F
Fortinet All Blogs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
P
Proofpoint News Feed
T
Tailwind CSS Blog
I
Intezer
C
CERT Recently Published Vulnerability Notes
U
Unit 42
V
V2EX
Cyberwarzone
Cyberwarzone
Recorded Future
Recorded Future
O
OpenAI News
Project Zero
Project Zero
有赞技术团队
有赞技术团队
Google DeepMind News
Google DeepMind News
Last Week in AI
Last Week in AI
Hugging Face - Blog
Hugging Face - Blog
Know Your Adversary
Know Your Adversary
C
Cybersecurity and Infrastructure Security Agency CISA
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术
博客园 - 叶小钗
S
Securelist
A
Arctic Wolf
The Cloudflare Blog
W
WeLiveSecurity
T
Threat Research - Cisco Blogs
博客园 - Franky

See you soon

哟,好久不见,无线打印 | See you soon 试试将文章版本化管理吧 | See you soon 使用 Quadlet 将 Podman 中的 Postgres 当作 systemd 服务运行 | See you soon 大他者,那个无时无刻都在盯着你的东西 | See you soon Laws of Software Engineering,软件工程定律 | See you soon 浅记多因素身份认证 | See you soon Linux 内核中的度量单位 | See you soon 重置 GPG 智能密钥 | See you soon 向 NAS 引入 samba | See you soon 无法重复键入的 Fcitx5 | See you soon ZFS 降级事故 | See you soon 记被 XanMod Kernel 和 AppArmor 联合坑的一次踩坑 | See you soon agent 的 skill 与 toolcall | See you soon 记一次服务器被挂恶意挖矿二进制 | See you soon 活着的 Arc | See you soon 令 acme.sh 使用 Cloudflare 的 DNS API 签发与续签证书 | See you soon 于 Tokio 中卸载 CPU Bound 任务 | See you soon 如我所见,梦破碎的时候 | See you soon 74LS 家族手册 | See you soon JDK Projects 备忘录 | See you soon 关于历史 | See you soon 用 curl 下载 OnePlus 的 ROM | See you soon 实用命令切片 | See you soon 再见,Oh My Zsh。 | See you soon 你不应该复用 strings.Builder | See you soon 博客的明日 | See you soon 被 AppArmor 击杀的 Dockge | See you soon AI 时代的自我 | See you soon 支持删除的布隆过滤器 | See you soon 基于栈的虚拟机与基于寄存器的虚拟机 | See you soon RVA23 包含了什么 | See you soon Rust 的边界检查是否已经有很大的进步 | See you soon 使用 Rust 编写操作系统:Barebones | See you soon 使用 Rust 编写操作系统:引言 | See you soon 编译器笔记:rope | See you soon 编译器笔记:CST | See you soon Paradoxical 札记 | See you soon 简单的相似去重算法(基于向量) | See you soon 简单的 CFG 语法分析方法 | See you soon 简单地使用 Caddy 实现 CORS 配置 | See you soon 让 OpenCV 可以被静态链接 | See you soon 图片搜索笔笺 | See you soon 电路板设计笔记-保护 | See you soon 使用 Rust 实现 SnowflakeId | See you soon 农夫乐事 FaQ 启示 | See you soon 使用 Rust 实现拓展系统札记 | See you soon 遗传学定律的代码实现 | See you soon EN:The Journey of Rust and Procps | See you soon ZH:Rust 与 Procps 之旅 | See you soon 使用 debootstrap 与 schroot 构建一个纯净环境 | See you soon GPG添加新的用户信息 | See you soon GSoC2024 笔记:使用 Rust 重新实现 procps | See you soon JWT 小册 | See you soon 使用密钥登录 SSH | See you soon Guava:Cache | See you soon 编译器笔记:增量编译 | See you soon Gradle秘境:添加一个类似modCompileOnly的依赖块 | See you soon Minecraft:原始经济系统设计简述 | See you soon TinyRemapper笔记 | See you soon MicroOS:进阶 | See you soon MicroOS:起步 | See you soon Swapfile 指北 | See you soon GPG 物理密钥的安装与密钥的迁移 | See you soon 用GPG签名告诉大家这就是我的提交 | See you soon DFS:深度优先搜索 | See you soon 文章翻译:从init.vim到init.lua | See you soon 目录遍历攻击 | See you soon 如何挂载.img文件,以及如何使用QEMU模拟arm64环境 | See you soon 在树莓派上编译 OpenCV | See you soon 关于卸载BlueStacks后遇到的问题 | See you soon
更加现代的 PaperMC Minecraft 插件设计指南 | See you soon
Krysztal Huang · 2025-05-06 · via See you soon

你还在为你的大型 PaperMC 插件性能差劲而烦恼吗?来看看这些 tips 吧。

常见卡顿原因

在 Minecraft 的设计里,你的插件所有逻辑都是串行的,当你插件的某部分逻辑无法在指定时间内完成相应的任务则会造成卡顿。

我们一般使用 TPS(Tick Per Second)来衡量服务器是否能按照预期的执行速度来执行整个游戏内加载好的逻辑,默认情况下这个数值是 20,当你的服务器当前 TPS 低于 20那么意味着你的服务器已经***过载(Overloaded)***了。

  • 计算瓶颈
    • 实体过多导致的过载
    • 算法缺陷
    • 加载项过多
    • 设计失误
  • IO 瓶颈
    • 主线程访问数据库
    • 主线程访问外部网络
    • 缓存过载

可以使用 PaperMC 自带的 Spark 简单分析瓶颈出现在什么地方。

但,这些都是有 tradeoff 的:我们需要牺牲一些实时性来利用更强大的计算资源利用

优化手段

优化将会围绕两个重要的点进行:优化计算瓶颈,还是优化 IO 瓶颈?

计算瓶颈

对于计算瓶颈而言除了优化算法以外还可以优化架构等,优化算法算是个很小的切入点

分离计算到其他线程

假设我们可以从原始架构访问到基础类型,那么我们可以通过值传递的方式构造一个函数 ,令 为我们预期的副作用或者预期的值,使得该副作用可以以干净的方式包装起来应用到目标上,这样就实现了封装副作用的目的

举个例子

// 以下代码是在主线程外进行的 //

// 通过各种包装使得 f 是一个可以安全地在主线程外计算的函数

var someHeavyComputing = f();

Bukkit.getScheduler().runTask(pluginInstance, () -> {

// 在完成计算后以同步的方式应用回计算结果,使得副作用可控

applyHeavyComputingResult(someHeavyComputing);

});

使用 Singleflight

如果对于一个表达式会反复求值,并且其输入和输出可以遇见地一致,那么可以使用 Singleflight 等方式缓存下来该表达式的结果,在接下来的运算中将有机会节约该次运算的计算损耗。

NOTE

当前 Java 生态并没有公认的 Singleflight 实现,因此请参考 Golang 的 Singleflight 实现自己实现一个

任务队列

可以通过任务队列的方式限制执行数量,每 tick 只取指定数量任务执行

由于任务队列处理器可以感知处理任务消耗的时间,因此甚至可以实现智能截断防止任务过多使得服务器过载

因此可以实现以下几种任务执行策略:

  • 溢出式
    • 该策略允许执行固定数量的任务,比如 1024 个任务、
    • 执行器只会执行小于等于 1024 个任务,多出来的任务本轮将不执行
  • 自动截断
    • 由于执行器可以感知已消耗的时间,因此可以在本轮任务即将超时或者已经超时时停止继续执行任务
  • 抛弃式
    • 只执行 1024 个任务,多余任务将会被抛弃

针对性缓存

可以利用精度缩减等方法来粗化搜索的粒度,并且实现针对性的缓存使得可以构建一个高效的缓存系统

精度缩减是一个很笼统的说法,举个例子:

  • 将坐标归一化到方块中心,以方块中心为中心点开始搜索实体
  • 由于已经归一化到方块中心并且搜索所有实体,该步骤可以缓存下来,本次 tick 都可以利用该缓存

对于这种很耗时的搜索,同时可以归约一下搜索范围为统一的几个值使得缓存可以被更高效利用:例如规定代码内使用的搜索范围为 3, 6, 8 等几个值

IO 瓶颈

很喜闻乐见的,有不少插件作者贪图简单选择直接在主线程里使用非常耗时的 IO 请求,这是难以避免的

分离 IO 逻辑到其他线程

该部分做法和上文提到的分离计算到其他线程做法一致,都是封装副作用在线程外计算,随后在主线程内应用。

不过你应该结合 Java 的异步基建来实现这一点:例如 Future