美团点评 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. 效果观察

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