Minecraft服务端卡顿问题排查分析

排查工具:arthas

今早无意查看我服Sponge服务端刷出大量的:

Can't keep up! Did the system time change, or is the server overloaded? Running 5400ms behind, skipping 108 tick(s)

也就代表某个线程跑满 tick主频不够用了。

但是得排查出具体原因,首先我们先使用htop看下CPU占用率,和主线程PID

发现占用挺高.....现在用查到的PID进入arthas里面

输入:dashboard

!https://s3-us-west-2.amazonaws.com/secure.notion-static.com/10e53952-7427-4118-a1b4-2100f11e5687/Untitled.png

发现服务端主线程长时间占用率还挺高。

然后尝试几次 thread -n 2 查询占用最高的2个线程

[arthas@307]$ thread -n 2
"Server thread" Id=20 cpuUsage=97% RUNNABLE
    at sun.reflect.Reflection.getCallerClass(Native Method)
    at java.lang.Class.getClassLoader(Class.java:683)
    at gregtech.common.pipelike.cable.tile.CableEnergyContainer.dispatchEnergyToNode(CableEnergyContainer.java)
    at gregtech.common.pipelike.cable.tile.CableEnergyContainer.acceptEnergyFromNetwork(CableEnergyContainer.java:46)
    at gregtech.api.capability.impl.EnergyContainerHandler.update(EnergyContainerHandler.java:150)
    at gregtech.api.metatileentity.MetaTileEntity.update(MetaTileEntity.java:557)
    at gregtech.api.metatileentity.MetaTileEntityHolder.func_73660_a(MetaTileEntityHolder.java:155)
    at org.spongepowered.common.event.tracking.TrackingUtil.tickTileEntity(TrackingUtil.java:237)
    at net.minecraft.world.WorldServer.updateTileEntity(WorldServer.java:4728)
    at net.minecraft.world.WorldServer.redirect$onUpdateTileEntities$zlk000(WorldServer.java:4712)
    at net.minecraft.world.World.func_72939_s(World.java:1838)
    at net.minecraft.world.WorldServer.func_72939_s(WorldServer.java:3930)
    at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:767)
    at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:397)
    at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:668)
    at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:526)
    at java.lang.Thread.run(Thread.java:748)

发现格雷科技里的线缆这个功能 dispatchEnergyToNode方法 CPU使用率异常高

然后去Github上看了GTCE的这一块代码

https://github.com/GregTechCE/GregTech/blob/master/src/main/java/gregtech/api/capability/impl/EnergyContainerHandler.java:150

https://github.com/GregTechCE/GregTech/blob/master/src/main/java/gregtech/common/pipelike/cable/tile/CableEnergyContainer.java

发现metaTileEntity实体触发更新导致以上流程里面几层循环调用,消耗大.....作者这么写心宽啊

好了我们要查一下metaTileEntity下面具体到游戏里的哪一个方块,从物理上解决....

从上面的代码可以看出来

at gregtech.api.metatileentity.MetaTileEntity.update(MetaTileEntity.java:557)

在做更新操作看看这个更新代码是在哪里调用的

我们使用arthas 的 watch 看看这个实体里面有什么

watch gregtech.api.metatileentity.MetaTileEntity shouldUpdate "params" -x 3 -b

params是调方法的参数 -b是标识调用前的内容 -x 3 是对象深度3层,这个对象在第三层貌似就获取到了坐标数据

我就取了一个查询耗时最长的一个实体到游戏里看看

游戏里/tppos 411 3 -478

最后查询到罪魁祸首应该是这些方块....

结果:阵列涡轮系统里的动力仓能源一直在更新导致卡服 (呕

大概思路就是这样吧,Minecraft和区块世界相关都在主线程上,所以开MC服务器还是用尽量高主频U,另外阿里的arthas排查JVM问题超级好用!