feat(faultguard): 单维度 tick 工作耗时连续超 300ms 自动关细粒度
- FaultGuard 新增 onTickSlow(double workMs):连续 3 次 > SLOW_TICK_MS(300ms) 关闭细粒度并行(保留维度并行),复用 fineDegraded 通道;恢复靠手动 /dimensionalripper fine on(setFine 内 FaultGuard.reset 会清计数)。 - LevelTickLoop.runIfCurrent finally:成功完成后上报本次维度纯工作耗时 (workNanos[0],不含收口等待)到 FaultGuard.onTickSlow。 - reset() 增加 slowTicks 清零。 背景:MSPT 爆高时细粒度并行放大单 tick 内调度/锁竞争开销,先关它把 tick 压回可控范围,避免拖成硬超时/假死。关闭安全:子任务在独立池内,不影响 维度 tick 收口,保留维度所有权。
This commit is contained in:
1 parent
1702d11d8f
commit
c24b35640b
2 files changed
+51
No files matched your search
@@ -26,6 +26,10 @@ public final class FaultGuard {
|
||||
private static final int AWAIT_TIMEOUT_THRESHOLD = 3;
|
||||
/** 看门狗:维度 tick 最晚完成时限(主线程等待上限)。 */
|
||||
public static final long AWAIT_TIMEOUT_MS = 30_000L;
|
||||
/** 单维度 tick 工作耗时超过该值(毫秒)视为一次"慢 tick"。 */
|
||||
public static final double SLOW_TICK_MS = 300.0;
|
||||
/** 连续慢 tick 达到该次数,自动关闭细粒度并行(保留维度并行)。 */
|
||||
private static final int SLOW_TICK_THRESHOLD = 3;
|
||||
|
||||
/** 细粒度是否已被自动关闭。 */
|
||||
private static volatile boolean fineDegraded = false;
|
||||
@@ -37,6 +41,7 @@ public final class FaultGuard {
|
||||
private static int fineFailures;
|
||||
private static int dimFailures;
|
||||
private static int awaitTimeouts;
|
||||
private static int slowTicks;
|
||||
|
||||
private FaultGuard() {
|
||||
}
|
||||
@@ -94,6 +99,47 @@ public final class FaultGuard {
|
||||
FineGrainScheduler.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报一次维度 tick 的工作耗时(毫秒)。连续 {@link #SLOW_TICK_THRESHOLD} 次超过
|
||||
* {@link #SLOW_TICK_MS} 时,自动关闭细粒度并行(保留维度并行)。
|
||||
* <p>
|
||||
* 与异常/超时通道的区别:这是"慢但没崩"的软故障。细粒度并行会放大单 tick 内的
|
||||
* 调度/锁竞争开销,MSPT 爆高时先关它能把 tick 耗时压回可控范围,避免拖成硬超时。
|
||||
* 关闭是安全的:细粒度子任务在独立池内,不影响维度 tick 收口,保留维度所有权。
|
||||
* <p>
|
||||
* 计数器为连续语义:一次正常(<= 阈值)会清零,容忍偶发尖峰。
|
||||
*
|
||||
* @param workMs 本次维度 tick 的纯工作耗时(不含收口等待);< 0 或非有限值忽略
|
||||
*/
|
||||
public static synchronized void onTickSlow(double workMs) {
|
||||
if (fineDegraded) {
|
||||
return;
|
||||
}
|
||||
if (!Double.isFinite(workMs) || workMs < 0) {
|
||||
return;
|
||||
}
|
||||
if (workMs <= SLOW_TICK_MS) {
|
||||
// 恢复正常:清零连续慢 tick 计数
|
||||
slowTicks = 0;
|
||||
return;
|
||||
}
|
||||
slowTicks++;
|
||||
ModZuozhi.LOGGER.warn("[FaultGuard] 维度 tick 工作耗时 {} ms 超过 {} ms(第 {} 次)",
|
||||
String.format(java.util.Locale.ROOT, "%.1f", workMs), SLOW_TICK_MS, slowTicks);
|
||||
if (slowTicks >= SLOW_TICK_THRESHOLD) {
|
||||
fineDegraded = true;
|
||||
reason = "维度 tick 连续 " + slowTicks + " 次超过 " + (long) SLOW_TICK_MS
|
||||
+ " ms,已自动关闭细粒度并行(保留维度并行),手动 /dimensionalripper fine on 可恢复";
|
||||
ModZuozhi.LOGGER.error("[FaultGuard] {}", reason);
|
||||
FineGrainScheduler.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/** 当前连续慢 tick 计数(status 诊断用)。 */
|
||||
public static synchronized int slowTickCount() {
|
||||
return slowTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* 看门狗:主线程等待维度 tick 完成后上报结果。
|
||||
*
|
||||
@@ -148,6 +194,7 @@ public final class FaultGuard {
|
||||
fineFailures = 0;
|
||||
dimFailures = 0;
|
||||
awaitTimeouts = 0;
|
||||
slowTicks = 0;
|
||||
ModZuozhi.LOGGER.info("[FaultGuard] 降级状态已重置");
|
||||
}
|
||||
}
|
||||
@@ -229,6 +229,10 @@ public final class LevelTickLoop implements Runnable, java.util.concurrent.Execu
|
||||
} finally {
|
||||
ThreadOwnershipDiagnostics.phase(this.level, "idle");
|
||||
progress.finish(System.nanoTime(), workNanos[0], completed[0]);
|
||||
// 慢 tick 保底:单维度工作耗时连续超阈 → FaultGuard 自动关细粒度(保留维度并行)。
|
||||
if (completed[0]) {
|
||||
FaultGuard.onTickSlow(workNanos[0] / 1_000_000.0);
|
||||
}
|
||||
synchronized (this) {
|
||||
this.ticking = false;
|
||||
if (this.running && !this.paused && !this.mainThreadHeld) {
|
||||
|
||||
Reference in new issue
Block a user