Druid连接池监控

1. 普通的web监控

阿里开源的连接池Druid自带了web监控的功能,具体的操作在其github的wiki上可以找到:配置_StatViewServlet配置 · alibaba/driud wiki

其实主要就是配置一个Servlet,但是github wiki上的做法只能在druid所在的项目中启用web服务的做法,在如今盛行的微服务架构中,很多时候druid所在的服务里并不提供web服务,这就需要额外的配置。其实druid本身也提供了这种功能,只是wiki里没有说。

druid本身可以通过启用JMX端口来将监控数据传输到远端进行处理,具体做法是:

  1. 在启动服务的时候加上JVM启动参数(下文说)
  2. 在远端启用web服务,配置StatViewServlet,在initParam中指定JMX地址

1.1 JVM启动参数:

-Djava.net.preferIPv4Stack=true
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=192.168.199.123
-Dcom.sun.management.jmxremote.port=9876
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

其中,-Djava.rmi.server.hostname一项指定了服务所在的IP地址,-Dcom.sun.management.jmxremote.port一项指定了JMX端口。

1.2 远程web工程Servlet配置

在web.xml里添加如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<!-- 远程访问JavaSE项目使用jmx连接 -->
<init-param>
<param-name>jmxUrl</param-name>
<param-value>service:jmx:rmi:///jndi/rmi://192.168.199.123:9876/jmxrmi</param-value>
</init-param>
<init-param>
<param-name>loginUsername</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>loginPassword</param-name>
<param-value>admin</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>

如果想快速打包启动,不依赖外部web容器,可以采用SpringBoot,用嵌入式的web容器启动,原理也是一样。具体做法是:

  1. 创建Servlet:
DruidStatViewServlet.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.tansc.test.springboot.config.druid;

import com.alibaba.druid.support.http.StatViewServlet;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

/**
* StatViewServlet
*/
@SuppressWarnings("serial")
@WebServlet(urlPatterns = "/druid/*",
initParams={
@WebInitParam(name="loginUsername",value="admin"),// 用户名
@WebInitParam(name="loginPassword",value="admin"),// 密码
@WebInitParam(name="jmxUrl",value="service:jmx:rmi:///jndi/rmi://192.168.199.123:9876/jmxrmi"),
@WebInitParam(name="resetEnable",value="false")// 禁用HTML页面上的“Reset All”功能
})
public class DruidStatViewServlet extends StatViewServlet {

}
  1. 在启动类上加上注解@ServletComponentScan("com.tansc.test.springboot")以扫描Servlet。

1.3 查看监控数据

上面的都配置好之后,启动服务,等服务启动成功之后,启动远端的web服务,然后访问web服务的/druid目录(与上面配置的匹配即可),例如在我本地起的:http://127.0.0.1:8080/druid

1.4 缺陷

  1. 这种做法是一对一的,也就是一个druid连接池实例必须对应一个StatViewServlet,一个StatViewServlet也只能对应一个druid实例。
  2. 切换环境不方便
  3. JMX重连不会成功
    • 虽然远端会有重连机制,但是在服务重启之后,重连总是报Connection refused,只能将远端的web服务重启才能成功连上(后来发现这其实没有重连,报错只是使用一个已经terminated的连接获取数据报错,具体见下一篇博文)

1.5 改进

对于上面提到的两点缺陷,可以用以下两个思路去改进:

  1. 动态创建servlet,模仿分布式服务的注册中心的形式来改造
    • Servlet本身不提供这样的API,但是应该是可以做到的,具体要继续探索。
  2. 使用配置文件
    • web.xml里面本身不能读取配置文件的值,但是可以通过继承StatViewServlet来实现。
  3. 需要分析源码

(2017-08-31 目前已经改造了,见我下一篇博文:Druid连接池监控的一次改造

1.6 性能损耗

当远程的web服务启动并且在浏览器里访问统计页面之后,该服务的内存变化如下:

2. 持久化/自定义传输监控记录

可以通过定制StatLogger实现,具体见其github的wiki:
怎么保存Druid的监控记录 · alibaba/driud wiki

参考资料

  1. 配置StatFilter · alibaba/driud wiki
    https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatFilter
  2. 非web项目如何配置Druid监控 - 若鱼的专栏 - CSDN博客
    http://blog.csdn.net/goldenfish1919/article/details/68941237
  3. Spring Boot 使用 Druid 和监控配置 - 小单的博客专栏 - CSDN博客
    http://blog.csdn.net/catoop/article/details/50925337
  4. 怎么保存Druid的监控记录 · alibaba/driud wiki
    https://github.com/alibaba/druid/wiki/%E6%80%8E%E4%B9%88%E4%BF%9D%E5%AD%98Druid%E7%9A%84%E7%9B%91%E6%8E%A7%E8%AE%B0%E5%BD%95