当前位置:首页 > 公众号精选 > 架构师社区
[导读]micrometer 中自带了很多其他框架的指标信息,可以很方便的通过 prometheus 进行采集和监控,常用的有 JVM 的信息,Http 请求的信息,Tomcat 线程的信息等。

前言

micrometer 中自带了很多其他框架的指标信息,可以很方便的通过 prometheus 进行采集和监控,常用的有 JVM 的信息,Http 请求的信息,Tomcat 线程的信息等。

对于一些比较活跃的框架,有些还是不支持的,比如 Dubbo。如果想监控 Dubbo 的一些指标,比如线程池的状况,我们需要手动去扩展,输出对应的线程池指标才行。

在这种情况下,肯定是没什么思路的,因为你不知道怎么去扩展,下面给大家介绍去做一件事情之前的思考,方式方法很重要。

  • Dubbo 有没有现成的实现?
  • 参考 micrometer 中指标的实现,依葫芦画瓢?

Dubbo 有没有现成的实现?

完整的实现应该没有,至少我还没用过,也没有那种去搜索引擎一搜就大把结果的现状,于是我在 Dubbo 的 Github 上找到了一个相关的项目 dubbo-spring-boot-actuator。

https://github.com/apache/dubbo-spring-boot-project/tree/master/dubbo-spring-boot-actuator

dubbo-spring-boot-actuator 看名称就知道,提供了 Dubbo 相关的各种信息端点和健康检查。从这里面也许能发现点有用的代码。

果不其然,在介绍页面中看到了想要的内容,线程池的指标数据,只不过是拼接成了字符串显示而已。

"threadpool": {
      "source": "management.health.dubbo.status.extras",
      "status": {
        "level": "OK",
        "message": "Pool status:OK, max:200, core:200, largest:0, active:0, task:0, service port: 12345",
        "description": null
      }
}

然后就去翻 dubbo-spring-boot-actuator 的代码了,没找到线程池这块的代码。后面在 dubbo.jar 中找到了 ThreadPoolStatusChecker 这个类,核心逻辑在这里面。现在已经解决了第一个问题,就是获取到 Dubbo 的线程池对象。



参考 micrometer 中指标的实现,依葫芦画瓢?

线程池对象能拿到了,各种数据也就能获取了。接下来的问题就是如何暴露出去给 prometheus 采集。

两种方式,一种是自定义一个新的端点暴露,一种是直接在已有的 prometheus 端点中增加指标数据的输出,也就是依葫芦画瓢。

看源码中已经有很多 Metrics 的实现了,我们也实现一个 Dubbo 线程池的 Metrics 即可。


上图框起来的就是一个已经存在的线程池 Metrics,可以直接复用代码。

实现的主要逻辑就是实现一个 MeterBinder 接口,然后将你需要的指标进行输出即可。于是打算在 bindTo 方法中获取 Dubbo 的线程池对象,然后输出指标。经过测试,在 MeterBinder 实例化的时候 Dubbo 还没初始化好,拿不到线程池对象,绑定后无法成功输出指标。

后面还是打算采用定时采样的方式来输出,自定义一个后台线程,定时去输出数据。可以用 Timer,我这图简单就直接 while 循环了。

/**
 * Dubbo线程池指标
 *
 * @author yinjihuan
 */
@Configuration
public class DubboThreadMetrics {
    @Autowired
    private MeterRegistry meterRegistry;
    private final IterableTAG = Collections.singletonList(Tag.of("thread.pool.name", "dubboThreadPool"));
    @PostConstruct
    public void init() {
        new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
                Map executors = dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY);
                for (Map.Entry entry : executors.entrySet()) {
                    ExecutorService executor = (ExecutorService) entry.getValue();
                    if (executor instanceof ThreadPoolExecutor) {
                        ThreadPoolExecutor tp = (ThreadPoolExecutor) executor;
                        Gauge.builder("dubbo.thread.pool.core.size", tp, ThreadPoolExecutor::getCorePoolSize)
                                .description("核心线程数")
                                .baseUnit("threads")
                                .register(meterRegistry);
                        Gauge.builder("dubbo.thread.pool.largest.size", tp, ThreadPoolExecutor::getLargestPoolSize)
                                .description("历史最高线程数")
                                .baseUnit("threads")
                                .register(meterRegistry);
                        Gauge.builder("dubbo.thread.pool.max.size", tp, ThreadPoolExecutor::getMaximumPoolSize)
                                .description("最大线程数")
                                .baseUnit("threads")
                                .register(meterRegistry);
                        Gauge.builder("dubbo.thread.pool.active.size", tp, ThreadPoolExecutor::getActiveCount)
                                .description("活跃线程数")
                                .baseUnit("threads")
                                .register(meterRegistry);
                        Gauge.builder("dubbo.thread.pool.thread.count", tp, ThreadPoolExecutor::getPoolSize)
                                .description("当前线程数")
                                .baseUnit("threads")
                                .register(meterRegistry);
                        Gauge.builder("dubbo.thread.pool.queue.size", tp, e -> e.getQueue().size())
                                .description("队列大小")
                                .baseUnit("threads")
                                .register(meterRegistry);
                        Gauge.builder("dubbo.thread.pool.taskCount", tp, ThreadPoolExecutor::getTaskCount)
                                .description("任务总量")
                                .baseUnit("threads")
                                .register(meterRegistry);
                        Gauge.builder("dubbo.thread.pool.completedTaskCount", tp, ThreadPoolExecutor::getCompletedTaskCount)
                                .description("已完成的任务量")
                                .baseUnit("threads")
                                .register(meterRegistry);
                    }
                }
            }
        }).start();
    }
}

指标信息:


配置线程池图表

创建一个新的 dashboard 配置图表,然后新建 panel 配置指标信息

图片

左侧配指标信息,右侧选择对应的图表格式。需要注意的是,如果有多个服务实例,Metrics 这边最好是根据服务实例来显示,需要在指标后面增加条件,如下:

dubbo_thread_pool_max_size_theads{application="$application", instance=~"$instance"}
图片



免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

摘 要:介绍了Windows最复杂的内核对象IOCP (I/O Completion Port输入/输出完成端口)的基本原理。利用完成端 口机制,应用程序能够为数百上千的用户服务。文章通过完成端口对象指定一定数量的线程,...

关键字: 完成端口 异步I/O 线程池 应用程序

↓推荐关注↓1.线程池原理我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为...

关键字: 线程池

点击上方蓝字关注下我呗之前分享过一次手写线程池-C语言版,然后有朋友问是否有C线程池实现的文章:其实关于C线程池的文章我好久以前写过,但估计很多新朋友都没有看到过,这里也重新发一下!本人在开发过程中经常会遇到需要使用线程...

关键字: 线程池

↓推荐关注↓1.线程池原理我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为...

关键字: 线程池

在《手写线程池-C语言版》中,已经实现了C语言版的线程池,如果我们也学过C的话,可以将其改为C版本,这样代码不管是从使用还是从感观上都会更简洁一些。对这些代码做从C到C的迁移主要用到了C三大特性中的封装,因此难度不大,对...

关键字: 线程池

1.线程池原理我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程...

关键字: 线程池

1.线程池原理我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程...

关键字: 线程池

在《手写线程池-C语言版》中,已经实现了C语言版的线程池,如果我们也学过C的话,可以将其改为C版本,这样代码不管是从使用还是从感观上都会更简洁一些。对这些代码做从C到C的迁移主要用到了C三大特性中的封装,因此难度不大,对...

关键字: 线程池

战略上藐视技术,战术上重视技术。

关键字: 线程池 行流程图

从问题出发,走一遍线程池的思想之旅,你会发现它很简单。

关键字: 线程池 代码
关闭
关闭