在spring boot應用監控線程池的狀態

今天在公衆號中看到了一篇教你如何監控 Java 線程池運行狀態 ,才記起來我之前也做過一樣的事情,但是沒有記錄下來,今天有空記下來。我會首先介紹一下監控的背景,監控方式,實例代碼及效果3個部分介紹。

背景

廢話不多說,做這個監控的背景很簡單,我們的項目都是以spring boot框架爲基礎開發的,代碼裏所有的異步線程都是通過@Async標籤標註的,並且標註的時候都是指定對應線程池的,如果不知@Async標註的,可以參考@Async異步線程池用法總結, 如果你用的不是spring,就參考上文提到的公衆號文章就好。再回到背景,我們當時經常遇到的問題就是這些線程池的隊列滿了之後,新的異步任務無法添加進去的錯誤,因此我們想對所有這種類型的線程池進行監控。

監控方式

再來介紹一下我們最終採用的方式 —— spring boot + statsd, 通過添加以下代碼就可以使statd能夠讀取/metrics接口中所有的指標併發送監控數據到statsd後端,statsd並不是本篇文章的重點,之後有時間再細講這部分的配置。

@Bean
public MetricsEndpointMetricReader metricsEndpointMetricReader(final MetricsEndpoint metricsEndpoint) {
    return new MetricsEndpointMetricReader(metricsEndpoint);
}

代碼及效果

我們所需要做的就是向/metrics接口添加線程池的指標,慶幸的是spring boot提供了良好的擴展機制,只需要實現PublicMetrics接口,實現其中的metrics方法你就能在/metrics中看到你新增的指標,上代碼:

@Component
public class AsyncThreadPoolMetrics implements PublicMetrics {

    public static final Logger LOG = LoggerFactory.getLogger(AsyncThreadPoolMetrics.class);

    private Map<String, ThreadPoolTaskExecutor> targetAsyncThreadPool;

    private static final String pattern = "async.task.%s.%s";

    @Autowired
    ApplicationContext context;

    @Override
    public Collection<Metric<?>> metrics() {
        try {
            if(targetAsyncThreadPool == null || targetAsyncThreadPool.size() == 0) {
                targetAsyncThreadPool = context.getBeansOfType(ThreadPoolTaskExecutor.class);
            }
            Collection<Metric<?>> result = new ArrayList<>();
            for (Map.Entry<String, ThreadPoolTaskExecutor> entry: targetAsyncThreadPool.entrySet()) {
                ThreadPoolTaskExecutor executor =  entry.getValue();
                result.add(new Metric<Number>(String.format(pattern, entry.getKey(), "aciveCount"), executor.getActiveCount(), new Date()));
                result.add(new Metric<Number>(String.format(pattern, entry.getKey(), "currentPoolSize"), executor.getPoolSize(), new Date()));
                result.add(new Metric<Number>(String.format(pattern, entry.getKey(), "maxPoolSize"), executor.getMaxPoolSize(), new Date()));
                result.add(new Metric<Number>(String.format(pattern, entry.getKey(), "currentSizeInQueue"), executor.getThreadPoolExecutor().getQueue().size(), new Date()));
            }
            return result;
        } catch (Exception e) {
            LOG.error("Async thread pool monitor exception", e);
        }
        return Collections.emptyList();
    }
}

從上面的代碼可以看出,我們監控的是多個線程池,原因很簡單,爲了使多種類型異步任務不互相影響,我們配置了多個線程池,多個線程池有不同的名字區分。

其實代碼很簡單,首先從容器中找到所有實現ThreadPoolTaskExecutor的bean,也就是我們要監控的線程池對象,取出正在活動的線程數,線程池的大小,配置最大可容納的線程數以及當前排隊的任務,當然還有很多其他指標,大家都可以試試,我只是選出當時我們需要的指標。當我們訪問此時應用的/metrics,效果如下,紅色框標註的便是我們添加的指標:

歡迎關注我的個人的博客www.zhijianliu.cn, 虛心求教,有錯誤還請指正輕拍,謝謝

版權聲明:本文出自志健的原創文章,未經博主允許不得轉載


發佈了23 篇原創文章 · 獲贊 10 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章