跳到主要内容
📖 本章预览

本章为预览版本,展示部分核心内容。完整内容包含详细源码解析、实战代码和面试要点,加入知识星球即可解锁全部章节。

第九章:线程池跑满了你还在看日志 — 监控告警体系

监控告警体系


9.1 问题场景

JDK 的 ThreadPoolExecutor 虽然暴露了 getActiveCount()getQueueSize() 等方法,但没有主动采集和推送机制。你不知道线程池什么时候快满了、任务排队多久了、有没有超时。等到出问题时,往往已经来不及了。

DynamicTP 构建了一套完整的监控体系:定时调度采集 → 指标转换 → 多通道输出,覆盖 25+ 监控指标,支持 Micrometer / Log / JMX / SPI 自定义四种采集通道。


9.2 DtpMonitor — 定时调度引擎

@Slf4j
public class DtpMonitor {

private static ScheduledExecutorService monitorExecutor;
private final DtpProperties dtpProperties;
private ScheduledFuture<?> monitorFuture;
private int monitorInterval;

/**
* 容器刷新时启动定时任务
*/
@Subscribe
public synchronized void onContextRefreshedEvent(
CustomContextRefreshedEvent event) {
// 间隔没变,不重建
if (monitorInterval == dtpProperties.getMonitorInterval()) {
return;
}
// 取消旧的定时任务
if (monitorFuture != null) {
monitorFuture.cancel(true);
}
if (monitorExecutor == null || monitorExecutor.isShutdown()) {
monitorExecutor = ThreadPoolCreator
.newScheduledThreadPool("dtp-monitor", 1);
}
monitorInterval = dtpProperties.getMonitorInterval();
// 按配置间隔定时执行
monitorFuture = monitorExecutor.scheduleWithFixedDelay(
this::run, 0, monitorInterval, TimeUnit.SECONDS);
}

private void run() {
Set<String> executorNames = DtpRegistry.getAllExecutorNames();
try {
checkAlarm(executorNames); // 先做告警检查
collectMetrics(executorNames); // 再做指标采集
} catch (Exception e) {
log.error("DynamicTp monitor, run error", e);
}
}
}

设计要点:

  • synchronized 保证并发安全(配置热更新时可能触发多次)
  • scheduleWithFixedDelay 而非 scheduleAtFixedRate:上一次执行完才开始计算下一次间隔,避免任务堆积
  • 支持热更新 monitorInterval:配置变更后自动取消旧任务、创建新任务
  • 异常被 catch 不会中断定时调度

9.3 25+ 监控指标全景

指标来源分三层:

基础指标 — 从 ExecutorAdapter 直接读取

private static ThreadPoolStats convertCommon(ExecutorAdapter<?> executor) {
ThreadPoolStats poolStats = new ThreadPoolStats();
// 线程指标(5个)
poolStats.setCorePoolSize(executor.getCorePoolSize());
poolStats.setMaximumPoolSize(executor.getMaximumPoolSize());
poolStats.setPoolSize(executor.getPoolSize());
poolStats.setLargestPoolSize(executor.getLargestPoolSize());
poolStats.setActiveCount(executor.getActiveCount());
// 队列指标(3个)
poolStats.setQueueCapacity(executor.getQueueCapacity());
poolStats.setQueueSize(executor.getQueueSize());
poolStats.setQueueRemainingCapacity(executor.getQueueRemainingCapacity());
// 任务指标(3个)
poolStats.setTaskCount(executor.getTaskCount());
poolStats.setCompletedTaskCount(executor.getCompletedTaskCount());
poolStats.setWaitTaskCount(executor.getQueueSize());
return poolStats;
}

超时/拒绝计数 — 从 ThreadPoolStatProvider 的 LongAdder 读取

poolStats.setRunTimeoutCount(provider.getRunTimeoutCount());
poolStats.setQueueTimeoutCount(provider.getQueueTimeoutCount());
poolStats.setRejectCount(provider.getRejectedTaskCount());

🔒 解锁完整内容

本章剩余内容需要解锁后查看

以上仅为本章部分预览内容,完整内容包含更多深度源码解析、实战代码和面试要点。

加入知识星球你将获得:

  • ✅ 全部 12 章完整内容 + 持续更新
  • ✅ 配套源码 + 实战项目
  • ✅ 一对一答疑 + 面试辅导
  • ✅ 简历优化 + 内推机会

📚 本章完整目录

以下为本章完整目录结构,加入知识星球即可解锁全部内容。

性能指标 — 从 PerformanceProvider 的快照读取

9.4 PerformanceProvider — 百分位统计

9.5 超时检测:HashedWheelTimer

9.6 CollectorHandler — 多通道输出

9.7 MicroMeterCollector — 24 个 Gauge 指标

9.8 实战:Prometheus + Grafana 监控大盘

9.9 告警配置