前言

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相关的各种信息端点和健康检查。从这里面也许能发现点有用的代码。

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

  1. "threadpool": {
  2. "source": "management.health.dubbo.status.extras",
  3. "status": {
  4. "level": "OK",
  5. "message": "Pool status:OK, max:200, core:200, largest:0, active:0, task:0, service port: 12345",
  6. "description": null
  7. }
  8. }

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

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

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

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

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

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

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

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

  1. /**
  2. * Dubbo线程池指标
  3. *
  4. * @author yinjihuan
  5. */
  6. @Configuration
  7. public class DubboThreadMetrics {
  8. @Autowired
  9. private MeterRegistry meterRegistry;
  10. private final Iterable<Tag> TAG = Collections.singletonList(Tag.of("thread.pool.name", "dubboThreadPool"));
  11. @PostConstruct
  12. public void init() {
  13. new Thread(() -> {
  14. while (true) {
  15. try {
  16. Thread.sleep(1000);
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
  21. Map<String, Object> executors = dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY);
  22. for (Map.Entry<String, Object> entry : executors.entrySet()) {
  23. ExecutorService executor = (ExecutorService) entry.getValue();
  24. if (executor instanceof ThreadPoolExecutor) {
  25. ThreadPoolExecutor tp = (ThreadPoolExecutor) executor;
  26. Gauge.builder("dubbo.thread.pool.core.size", tp, ThreadPoolExecutor::getCorePoolSize)
  27. .description("核心线程数")
  28. .baseUnit("threads")
  29. .register(meterRegistry);
  30. Gauge.builder("dubbo.thread.pool.largest.size", tp, ThreadPoolExecutor::getLargestPoolSize)
  31. .description("历史最高线程数")
  32. .baseUnit("threads")
  33. .register(meterRegistry);
  34. Gauge.builder("dubbo.thread.pool.max.size", tp, ThreadPoolExecutor::getMaximumPoolSize)
  35. .description("最大线程数")
  36. .baseUnit("threads")
  37. .register(meterRegistry);
  38. Gauge.builder("dubbo.thread.pool.active.size", tp, ThreadPoolExecutor::getActiveCount)
  39. .description("活跃线程数")
  40. .baseUnit("threads")
  41. .register(meterRegistry);
  42. Gauge.builder("dubbo.thread.pool.thread.count", tp, ThreadPoolExecutor::getPoolSize)
  43. .description("当前线程数")
  44. .baseUnit("threads")
  45. .register(meterRegistry);
  46. Gauge.builder("dubbo.thread.pool.queue.size", tp, e -> e.getQueue().size())
  47. .description("队列大小")
  48. .baseUnit("threads")
  49. .register(meterRegistry);
  50. Gauge.builder("dubbo.thread.pool.taskCount", tp, ThreadPoolExecutor::getTaskCount)
  51. .description("任务总量")
  52. .baseUnit("threads")
  53. .register(meterRegistry);
  54. Gauge.builder("dubbo.thread.pool.completedTaskCount", tp, ThreadPoolExecutor::getCompletedTaskCount)
  55. .description("已完成的任务量")
  56. .baseUnit("threads")
  57. .register(meterRegistry);
  58. }
  59. }
  60. }
  61. }).start();
  62. }
  63. }

指标信息:

配置线程池图表

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

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

  1. dubbo_thread_pool_max_size_theads{application="$application", instance=~"$instance"}

关于作者:尹吉欢,简单的技术爱好者,《Spring Cloud微服务-全栈技术与案例解析》, 《Spring Cloud微服务 入门 实战与进阶》作者, 公众号猿天地发起人。

用了很多年Dubbo,连Dubbo线程池监控都不知道,觉得自己很厉害?的更多相关文章

  1. Hippo4J v1.3.1 发布,增加 Netty 监控上报、SpringCloud Hystrix 线程池监控等特性

    文章首发在公众号(龙台的技术笔记),之后同步到博客园和个人网站:xiaomage.info Hippo4J v1.3.1 正式发布,本次发布增加了 Netty 上传动态线程池监控数据.适配 Hystr ...

  2. java线程池监控

    原因 最近在完善公司的基础发布平台的时候,使用到了一线程去做一些异步的事情,在开发环境和测试环境验证没有任何问题,但是在程序在生产运行一段时间后,发现没有得到自己想要的结果,为此开始了漫长的排查bug ...

  3. Java并发(六)线程池监控

    目录 一.线程池监控参数 二.线程池监控类 三.注意事项 在上一篇博文中,我们介绍了线程池的基本原理和使用方法.了解了基本概念之后,我们可以使用 Executors 类创建线程池来执行大量的任务,使用 ...

  4. 基于Spring Boot的线程池监控方案

    前言 这篇是推动大家异步编程的思想的线程池的准备篇,要做好监控,让大家使用无后顾之忧,敬畏生产. 为什么需要对线程池进行监控 Java线程池作为最常使用到的并发工具,相信大家都不陌生,但是你真的确定使 ...

  5. java开发两年,这些线程知识你都不知道,你怎么涨薪?

    前言 什么是线程:程序中负责执行的哪个东东就叫做线程(执行路线,进程内部的执行序列),或者说是进程的子任务. Java中实现多线程有几种方法 继承Thread类: 实现Runnable接口: 实现Ca ...

  6. 理解线程池到走进dubbo源码

    引言 合理利用线程池能够带来三个好处. ​ 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. ​ 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. ...

  7. Dubbo学习笔记8:Dubbo的线程模型与线程池策略

    Dubbo默认的底层网络通讯使用的是Netty,服务提供方NettyServer使用两级线程池,其中 EventLoopGroup(boss) 主要用来接受客户端的链接请求,并把接受的请求分发给 Ev ...

  8. Dubbo 源代码分析八:再说 Provider 线程池被 EXHAUSTED

    转自:http://manzhizhen.iteye.com/blog/2391177 在上回<Dubbo源代码实现六>中我们已经了解到,对于Dubbo集群中的Provider角色,有IO ...

  9. Dubbo扩展点应用之四线程池

    线程池也是Dubbo自动自适应扩展点之一,也可以自定义线程池.Dubbo中已实现的线程池扩展点有: 其中框架提供的线程池都是通过创建真实的业务线程池进行操作的,目前线程池模型中有两个和Java中线程池 ...

随机推荐

  1. memcached+magent的集群部署详细过程

    问题描述 Memcached在实现分布集群部署时, Memcached服务端的之间是没有通讯的,服务端是伪分布式,实现分布式是由客户端实现的,客户端实现了分布式算法把数据保存到不同的Memcached ...

  2. mysql .sock丢时候如何链接数据库

    在mysql服务器本机上链接mysql数据库时,经常会噢出现mysql.sock不存在,导致无法链接的问题,这是因为如果指定localhost作为一个主机名,则mysqladmin默认使用unix套接 ...

  3. 【Oracle】查看某个角色中有什么权限

    select * from role_sys_privs  where role='DBA'; 查看dba都有什么系统权限 select * from role_sys_privs where rol ...

  4. centos7安装宝塔面板

    在终端下执行如下命令 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install.s ...

  5. Numpy的一些学习记录

    Numpy的一些记录 产生numpy.array的方式 import numpy as np arr1 = np.array([1, 2, 3]) print(arr1) arr2 = np.zero ...

  6. thinkphp如何实现伪静态

    去掉 URL 中的 index.php ThinkPHP 作为 PHP 框架,是单一入口的,那么其原始的 URL 便不是那么友好.但 ThinkPHP 提供了各种机制来定制需要的 URL 格式,配合 ...

  7. MySQL主从配置This operation cannot be performed with a running slave io thread; run STOP SLAVE IO_THREAD FOR CHANNEL '' first.

    MySQL主从配置This operation cannot be performed with a running slave io thread; run STOP SLAVE IO_THREAD ...

  8. code-server Command ' ' not found

    由于通过一些特殊的方式登录linux用户后,全局变量不会自动加载,需要在 vscode 的 bash terminal手动读取 输入 source /etc/profile 或者vim ~/.bash ...

  9. java虚拟机——轻松搞懂jvm

    一.JVM体系结构概述 JVM位置 JVM体系结构 1.1 类加载器 ClassLoader   类加载器(ClassLoader)负责加载class文件,class文件在文件开头有特定的文件标示,并 ...

  10. Python Data Structure and Algorithms Tutorial

    Python - Algorithm Design - Tutorialspoint https://www.tutorialspoint.com/python_data_structure/pyth ...