美團點評 Cat監控 線程池監控

      在日常項目開發中,我們經常會遇到需要異步處理的任務,例如日誌服務,監控服務等。有一定開發經驗的同學首先就會想到使用線程池,因爲“在線程池中執行任務”比“爲每個任務創建一個線程”更有優勢,通過重用現有的線程,可以避免線程在不斷創建、銷燬過程中產生的開銷。在java開發中,一般做法就是基於ThreadPoolExecutor類,自定義corePoolSize, maxPoolSize, ThreadFactory等參數來創建一個線程池工具類。但是,線程池也不是沒有缺點的,對於開發者而言,我們很難在項目上線之前準確地預估業務的規模,所以,如何合理地爲線程池設置corePoolSize,maxPoolSize是一個比較難把握的事情,設置不合理會導致不能達到預計的性能,甚至會引發線上故障。不過,利用ThreadPoolExecutor爲我們提供的一些監控api,我們可以做到對線程池進行實時監控和調優。本文將利用如下幾個API,並結合Cat提供的拓展功能,實現對線程池的持續監控。

1.自定義線程池

如下代碼是我用來測試的一個線程池工具類

public class ThreadPoolManager<T> {

    /**
     * 根據cpu的數量動態的配置核心線程數和最大線程數
     */
    //private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    /**
     * 核心線程數 = CPU核心數 + 1
     */
    private static final int CORE_POOL_SIZE = 20;
    /**
     * 線程池最大線程數 = CPU核心數 * 2 + 1
     */
    private static final int MAXIMUM_POOL_SIZE = 25;

    private static final int QUEUE_SIZE = 1000;

    /**
     * 非核心線程閒置時超時1s
     */
    private static final int KEEP_ALIVE = 3;


    /**
     * 線程池的對象
     */
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
            KEEP_ALIVE, TimeUnit.SECONDS, new ArrayBlockingQueue<>(QUEUE_SIZE),
            Executors.defaultThreadFactory(), new DiscardPolicyWithLog());

    /**
     * 要確保該類只有一個實例對象,避免產生過多對象消費資源,所以採用單例模式
     */
    private ThreadPoolManager() {
        
    }

    private static ThreadPoolManager sInstance;


    public static ThreadPoolManager getsInstance() {
        if (sInstance == null) {
            synchronized (ThreadPoolManager.class) {
                if (sInstance == null) {
                    sInstance = new ThreadPoolManager();
                }
            }
        }
        return sInstance;
    }

    /**
     * 開啓一個無返回結果的線程
     * @param r
     */
    public void execute(Runnable r) {
        executor.execute(r);
    }

    /**
     * 開啓一個有返回結果的線程
     *
     * @param r
     * @return
     */
    public Future<T> submit(Callable<T> r) {
        // 把一個任務丟到了線程池中
        return executor.submit(r);
    }

    /**
     * 把任務移除等待隊列
     *
     * @param r
     */
    public void cancel(Runnable r) {
        if (r != null) {
            executor.getQueue().remove(r);
        }
    }
}

2.加入Cat監控

    假設你的項目已經集成了cat監控,那麼,利用cat提供的SPI拓展能力,我們可以監控任何需要關注的系統運行時指標。我們現在想要監控線程池運行時的一些指標,幫助我們更好的優化線程池配置,提高系統性能。在以上線程池工具類的構造方法里加入如下代碼,就可以實現。

private ThreadPoolManager() {
        StatusExtensionRegister.getInstance().register(new StatusExtension() {
            @Override
            public String getId() {
                return "mqtt_msg_pool_monitor";
            }

            @Override
            public String getDescription() {
                return "mqtt消息處理線程池監控";
            }

            @Override
            public Map<String, String> getProperties() {
                Map<String,String> map = new HashMap<>();
                //線程池曾經創建過的最大線程數量
                map.put("largest-pool-size", String.valueOf(executor.getLargestPoolSize()));
                map.put("max-pool-size", String.valueOf(executor.getMaximumPoolSize()));
                map.put("core-pool-size", String.valueOf(executor.getCorePoolSize()));
                map.put("current-pool-size", String.valueOf(executor.getPoolSize()));
                map.put("queue-size", String.valueOf(executor.getQueue().size()));

                return map;
            }
        });
    }

3. 效果觀察

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章