Spring Boot应用中监控tomcat,druid连接池状态
这篇文章记录一下如何在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, 虚心求教,有错误还请指正轻拍,谢谢
版权声明:本文出自志健的原创文章,未经博主允许不得转载
更多推荐
所有评论(0)