如下分析基於pinpoint1.7.1版本java
pinpoint agent主要使用到的異步線程有4個sql
DeadlockMonitorThread : 死鎖監測線程,執行一次休眠60s異步
public DeadlockMonitorThread(DeadlockThreadRegistry deadlockThreadRegistry, long intervalMillis) { this.deadlockMonitorTask = new DeadlockMonitorTask(deadlockThreadRegistry, intervalMillis); this.deadlockMonitorThread = new Thread(deadlockMonitorTask, "Pinpoint-deadlock-monitor"); this.deadlockMonitorThread.setDaemon(true); // for preload deadlockMonitorTask.doTask(); }
AgentInfoSender: agent信息上報定時任務,是個timer,3秒上報一次jvm
DefaultAgentStatMonitor: agent狀態信息上報(jvm狀態等),線程數爲1的定時線程池(ScheduledExecutorService),延遲5秒執行,每5秒上報一次this
private final ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1, new PinpointThreadFactory("Pinpoint-stat-monitor", true));
TcpDataSender: 調用鏈數據上報通道,單線程,數據隊列(LinkedBlockingQueue)大小5120,重試隊列(LinkedBlockingQueue)大小1024,底層通迅使用的Netty線程
以上除了數據上報較爲複雜外,其它幾個都是定時執行的單線程程序日誌
調用鏈數據上報分爲兩種code
數據上報流程blog
public boolean execute(T data) { if (data == null) { if (isWarn) { logger.warn("execute(). data is null"); } return false; } if (!isRun.get()) { if (isWarn) { logger.warn("{} is shutdown. discard data:{}", executorName, data); } return false; } boolean offer = queue.offer(data); if (!offer) { if (isWarn) { logger.warn("{} Drop data. queue is full. size:{}", executorName, queue.size()); } } return offer; }
private void doExecute() { drainStartEntry: while (isRun()) { try { Collection<T> dtoList = getDrainQueue(); int drainSize = takeN(dtoList, this.maxDrainSize); if (drainSize > 0) { doExecute(dtoList); continue; } while (isRun()) { T dto = takeOne(); if (dto != null) { doExecute(dto); continue drainStartEntry; } } } catch (Throwable th) { logger.warn("{} doExecute(). Unexpected Error. Cause:{}", executorName, th.getMessage(), th); } } flushQueue(); }
還有一個UDP的數據上報通道,除了底層協議不一樣外,其它和TCP上報同樣隊列
數據上報流程
總結
agent使用的異步線程都是單線程
數據上報都是先把數據放入隊列中,當即返回,隊列大小可配置,默認5120
底層數據上報通迅是基於Netty的NIO
因爲調用鏈監控的粒度很是細,因此過多的日誌打印會對應用形成影響,要避免沒必要要的日誌,合理設置日誌級別,線上使用的日誌級別要配置高一些