在这之前先科普一下什么是tick循环

几乎所有的游戏(包括minecraft) 都有一个“大循环”驱动,游戏服务器和玩家发生的事件被切片成一个个小循环,也就是”tick”
对于minecraft,每次tick发生时,游戏服务器会做以下事

处理玩家事件(如移动,放置/破坏 方块,攻击实体)
更新玩家和其他实体之间的位置
将服务器发生的事件更新至客户端(如方块状态改变,实体移动操作)
…..还有很多

总之,每个tick中都包含了大量逻辑处理
在minecraft中,每50毫秒会运行一个tick,即一秒钟会运行20个tick
https://spark.lucko.me/docs/assets/images/ticks-linear-719b3df9e469b960429fa91e007e4a5b.png
当然,每个tick的工作量并不相同,这取决于游戏里发生了什么事,事实上永远不会如此规律

对于spigot服务器,服务器正常运行时执行一个tick的完整时间应当小于等于50ms,如果一个花费时间小于50毫秒,服务器会让它休眠直至下一个tick运行。为什么要这么做?如果服务器不将tick隔开,那么一切都会发生的很“快”
image.png
如图,这是spark生成的分析报告,其中在主线程上,有81%的时间用于等待下一个tick发生。数据分析是平均而言的,这意味着服务器运行良好,每一个tick都在不到50ms内被处理完,完全不会体验到卡顿的感觉

注意,前面提到数据分析是平均的,假设服务器大多数时间都能良好的运行tick,但偶尔有一个tick处理了1000ms,因为数据是平均而言的,极值被抹掉了,对着数据报告完全无从下手,这也是为什么性能分析不需要太长时间的原因;那么会有什么后果?在游戏中会是不定时的造成卡顿,可能是几分钟来一次,严重的话主线程挂起太久直接就蹦了

综上所述,当少量tick(或一个tick)需要很长时间才能执行的时候就会发生“卡顿峰值”,通过正常生成的分析数据是很难找出问题的,幸运的是spark有工具能很快定位到这些烦人的峰值

  1. 使用 /spark tickmonitor 来实时检测滞后

    为了确定峰值卡顿的原因,我们需要先将峰值卡顿与其他滞后区分开。后面可以跟一个参数,这是服务器初始必须赶上的值。
    image.png
    接下来,只需要等待,将游戏中的卡顿与输出信息对齐,会很明显的看到“卡顿峰值”
    (手动制造了一个卡顿峰值hh)
    image.png

  2. 使用 /spark profiler –only-ticks-over 查找原因

    加上 –only-ticks-over选项后spark只会分析持续时间超过给定阈值的tick。这意味着过滤掉了大部分正常tick,只留下了造成峰值卡顿的tick。如上,这个tick超过了3000ms,执行/spark profiler –only-ticks-over 2000
    注意,后面跟着的值必须小于卡顿操作运行的毫秒数,这里使用2000确定能将该操作的tick加入进来

最后,运行/spark profiler –stop
ZXWSFKAG`0MRXHB`_P.png
造成卡顿的原因非常明显了,是com.blank038.spring.RewardData这个类下,接下来范围就缩小了,只需要注重修改插件的错误就好了。搭配上这个加上合理利用timings和spark分析报告,就能准确的处理每一次卡顿不至于束手无策

参考https://spark.lucko.me/docs