这篇文章记录一下如何在spring boot中监控tomcat,druid连接池状态,之前我写过一篇文章介绍过类似的,具体背景和监控数据的收集部分这里就不赘述,可以参考在SPRING BOOT应用监控线程池的状态

背景

随着流量的增大,我们急需监控各个微服务部署的tomcat和数据库连接池状态,以此来了解线上连接池配置是否满足要求,不存在性能上的问题。

数据收集

JMX

再介绍怎么监控连接池状态之前,先来了解一下JMX, JMX在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。通常使用JMX来监控系统的运行状态或管理系统的某些方面,比如清空缓存、重新加载配置文件等。

tomcat和druid在启动后都会在JMX中注册自己的Mbean, 其中Mbean有关于连接池状态的属性,因此只需要定时读取Mbean中的这部分属性就能做到对线程池的监控。

怎么试着查看JMX呢?最简单的办法就是通过jvisualvm,打开已经启动的spring boot项目,当然前提是要在jvisualvm中提前安装好mbeans的插件,之后我们能发现有一个Mbeans标签,点击它就能看到所有注册到JMX的Mbean, 其中就有Tomcat和Druid的Mbean,顺着它们的树状结构查看它们支持的所有属性值,这些属性值就是正在运行的spring boot程序的当前状态,挑出我们最关心的属性继续往下看。

 

还是和之前一样利用spring boot actuator, 它能和statsd集成,并定时将/metrics中的监控数据发送出去,因此我们只需要实现PublicMetrics接口,而在metrics方法中读取tomcat和druid的Mbean数据,具体可以参考下面的代码:

监控Tomcat连接池

@Component
public class TomcatPublishMetrics implements PublicMetrics {

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

    @Autowired
    private MBeanServer mbeanServer;

    @Override
    public Collection<Metric<?>> metrics() {
        try {
            Set<ObjectName> objectNames = mbeanServer.queryNames(new ObjectName("Tomcat:type=ThreadPool,*"), null);
            Collection<Metric<?>> result = new ArrayList<>();
            if (objectNames != null && objectNames.size() == 1) {
                for (ObjectName objectName : objectNames) {
                    int maxThreads = (Integer) mbeanServer.getAttribute(objectName, "maxThreads");
                    int currentThreadCount = (Integer) mbeanServer.getAttribute(objectName, "currentThreadCount");
                    int currentThreadsBusy = (Integer) mbeanServer.getAttribute(objectName, "currentThreadsBusy");
                    long connectionCount = (Long) mbeanServer.getAttribute(objectName, "connectionCount");
                    int maxConnections = (Integer) mbeanServer.getAttribute(objectName, "maxConnections");
                    result.add(new Metric<Number>("tomcat.thread.busy", currentThreadsBusy, new Date()));
                    result.add(new Metric<Number>("tomcat.thread.max", maxThreads, new Date()));
                    result.add(new Metric<Number>("tomcat.thread.current", currentThreadCount, new Date()));
                    result.add(new Metric<Number>("tomcat.thread.connectionCount", connectionCount, new Date()));
                    result.add(new Metric<Number>("tomcat.thread.maxConnections", maxConnections, new Date()));
                }
            } else {
                LOG.warn("Tomcat thread pool monitor failed");
            }
            return result;
        } catch (Exception e) {
            LOG.error("Tomcat thread pool monitor exception", e);
        }
        return Collections.emptyList();
    }
}

监控Druid连接池

@Component
public class DruidPoolPublishMetrics implements PublicMetrics {

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

    @Autowired
    private MBeanServer mbeanServer;

    @Override
    public Collection<Metric<?>> metrics() {
        try {
            Set<ObjectName> objectNames = mbeanServer.queryNames(new ObjectName("com.alibaba.druid.pool:type=DruidDataSource,*"), null);
            Collection<Metric<?>> result = new ArrayList<>();
            if (objectNames != null && objectNames.size() == 1) {
                for (ObjectName objectName : objectNames) {
                    long errorCount = (Long) mbeanServer.getAttribute(objectName, "ErrorCount");
                    int waitThreadCount = (Integer) mbeanServer.getAttribute(objectName, "WaitThreadCount");
                    long resetCount = (Long) mbeanServer.getAttribute(objectName, "ResetCount");
                    int activeCount = (Integer) mbeanServer.getAttribute(objectName, "ActiveCount");
                    long rollbackCount = (Long) mbeanServer.getAttribute(objectName, "RollbackCount");
                    int maxActive = (Integer) mbeanServer.getAttribute(objectName, "MaxActive");
                    result.add(new Metric<Number>("druid.pool.errorCount", errorCount, new Date()));
                    result.add(new Metric<Number>("druid.pool.waitThreadCount", waitThreadCount, new Date()));
                    result.add(new Metric<Number>("druid.pool.resetCount", resetCount, new Date()));
                    result.add(new Metric<Number>("druid.pool.activeCount", activeCount, new Date()));
                    result.add(new Metric<Number>("druid.pool.rollbackCount", rollbackCount, new Date()));
                    result.add(new Metric<Number>("druid.pool.maxActive", maxActive, new Date()));
                }
            } else {
                LOG.warn("DruidPool monitor failed");
            }
            return result;
        } catch (Exception e) {
            LOG.error("DruidPool monitor exception", e);
        }
        return Collections.emptyList();
    }
}

总结

这篇文章介绍了通过读取JMX中相应的Mbean的数据进行收集并监控,如果其他的监控指标注册在JMX中,例如对redis的连接池,也可以采用类似的方法收集。

 

欢迎关注我的个人的博客www.zhijianliu.cn, 虚心求教,有错误还请指正轻拍,谢谢

版权声明:本文出自志健的原创文章,未经博主允许不得转载

发表评论

电子邮件地址不会被公开。