Druid监控页面配置与实战:从连接到SQL的全链路性能透视
2026/8/5 5:23:11 网站建设 项目流程

1. 项目概述:为什么我们需要Druid监控页面?

在任何一个稍微有点规模的Java应用里,数据库连接池都是那个默默无闻但又至关重要的“心脏”。它负责管理应用与数据库之间的连接,连接的创建、销毁、复用,都直接影响着应用的响应速度和稳定性。我见过太多线上事故,追根溯源,最后发现是连接池配置不当:连接泄漏导致数据库连接数耗尽,应用彻底瘫痪;或者慢SQL堆积,拖垮整个数据库实例。这时候,光看应用日志是没用的,你需要一双能直接透视连接池内部运行状态的眼睛。

这就是Druid监控页面的价值所在。Druid不仅仅是阿里巴巴开源的一个高性能数据库连接池,它更是一个自带强大监控能力的“瑞士军刀”。其内置的监控页面(StatViewServlet)提供了一个Web可视化界面,让你能实时、直观地看到连接池的每一个关键指标:活跃连接数、等待线程数、执行SQL的统计、慢SQL清单等等。这比在代码里打日志,或者依赖第三方复杂的APM工具要直接得多。对于开发者和运维来说,配置好这个监控页面,就等于在数据库访问这个关键路径上装了一个高清摄像头,任何风吹草动都尽在掌握。

今天,我就结合自己多年在项目中的实战经验,从零开始,带你彻底搞懂Druid监控页面的配置、使用以及那些官方文档里不会写的“坑”。无论你是刚接触Druid的新手,还是想优化现有监控的老手,这篇文章都能给你提供可直接落地的方案。

2. Druid监控页面的核心配置详解

配置Druid监控页面,本质上是在Web应用中注册一个特殊的Servlet(StatViewServlet)和一个Filter(WebStatFilter)。这个过程并不复杂,但里面的每一个参数都关乎监控的准确性、安全性和性能。下面我们分Spring Boot和传统Servlet两种环境来详细拆解。

2.1 基于Spring Boot的配置(推荐)

Spring Boot的自动配置让事情变得简单,但我们通常需要一些自定义配置来满足生产环境的要求。主要涉及application.yml(或application.properties)和可能的配置类。

2.1.1 基础YAML配置与参数解析

首先,在pom.xml中确保引入了Druid Spring Boot Starter依赖。

<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.20</version> <!-- 请使用最新稳定版本 --> </dependency>

然后,在application.yml中进行核心配置:

spring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: # 1. 数据库连接基本配置 url: jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: your_username password: your_password driver-class-name: com.mysql.cj.jdbc.Driver # 2. 连接池核心参数配置(监控数据的基础) initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000 # 获取连接超时时间,单位毫秒 test-on-borrow: false # 不建议开启,性能差 test-on-return: false test-while-idle: true # 必须开启,依靠空闲连接检测 validation-query: SELECT 1 time-between-eviction-runs-millis: 60000 # 空闲连接检测周期 min-evictable-idle-time-millis: 300000 # 连接最小空闲时间 # 3. 监控页面(StatViewServlet)配置 stat-view-servlet: enabled: true # 开启内置监控页面 url-pattern: /druid/* # 访问路径,可自定义 reset-enable: false # 生产环境务必关闭!否则可以通过页面重置所有数据 login-username: admin # 监控页登录用户名,生产环境必须设置! login-password: admin123 # 监控页登录密码 allow: 192.168.1.100, 127.0.0.1 # 白名单,不配置或为空则允许所有访问(危险!) deny: 192.168.1.73 # 黑名单,优先级高于allow # 4. Web关联监控(WebStatFilter)配置 web-stat-filter: enabled: true # 开启Web应用监控 url-pattern: /* # 过滤所有URL exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" # 排除静态资源和监控页面本身 session-stat-enable: true # 开启session统计 session-stat-max-count: 1000 # session最多统计个数 # 5. SQL监控与防火墙配置 filter: stat: enabled: true # 开启SQL监控 log-slow-sql: true # 记录慢SQL slow-sql-millis: 2000 # 慢SQL阈值,单位毫秒 merge-sql: true # 合并相似的SQL,便于统计 wall: enabled: true # 开启SQL防火墙,防御SQL注入 config: drop-table-allow: false # 禁止删表语句

关键参数解读与避坑指南:

  • reset-enable: false:这是血泪教训。曾经有测试同学误点了监控页面的“重置”按钮,导致线上运行了几周的监控数据瞬间清零,无法追溯历史问题。生产环境一定要关闭。
  • login-username/passwordallow/deny:监控页面会暴露数据库连接数、SQL语句等敏感信息。绝对不要在公网环境不设密码和IP限制。allow支持IP和子网掩码格式(如192.168.1.0/24)。
  • test-while-idlevalidation-query:这是保证连接有效性的黄金组合。通过定期检查空闲连接,及时剔除失效连接,避免应用拿到已断开的数据库连接报错。
  • slow-sql-millis:这个值需要根据你的业务数据库性能来定。对于OLTP业务,1-2秒可能就算慢了;对于报表类查询,5-10秒也可能可以接受。设置后,慢SQL会在监控页的“SQL监控”和“慢SQL”标签页高亮显示。

2.1.2 通过Java Config进行高级定制

如果YAML配置不能满足你的需求,比如需要更复杂的Filter链,或者要集成到自定义的登录认证体系中,你可以使用@Configuration类。

@Configuration public class DruidConfig { /** * 自定义StatViewServlet配置。 * 通常用YAML配置就够了,这里演示如何添加自定义初始化参数。 */ @Bean public ServletRegistrationBean<StatViewServlet> statViewServlet() { ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*"); // 添加初始化参数 Map<String, String> initParams = new HashMap<>(); initParams.put("loginUsername", "admin"); initParams.put("loginPassword", "admin123"); initParams.put("resetEnable", "false"); // 添加一个自定义参数,比如页面标题 initParams.put("sysTitle", "我的业务系统监控中心"); registrationBean.setInitParameters(initParams); return registrationBean; } /** * 自定义WebStatFilter配置。 * 可以更精细地控制需要统计的URL和Session。 */ @Bean public FilterRegistrationBean<WebStatFilter> webStatFilter() { FilterRegistrationBean<WebStatFilter> registrationBean = new FilterRegistrationBean<>(new WebStatFilter()); registrationBean.setUrlPatterns(Arrays.asList("/*")); Map<String, String> initParams = new HashMap<>(); initParams.put("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); // 开启Profile,可以查看调用栈(对性能有轻微影响,调试时开启) initParams.put("profileEnable", "true"); registrationBean.setInitParameters(initParams); return registrationBean; } /** * 自定义Druid数据源配置,覆盖自动配置的属性。 * 这里可以注入在YAML中配置的`spring.datasource.druid`下的属性。 */ @ConfigurationProperties("spring.datasource.druid") @Bean(initMethod = "init", destroyMethod = "close") public DataSource dataSource() throws SQLException { // 此处会读取YAML配置,同时可以在这里进行编程式覆盖 DruidDataSource datasource = new DruidDataSource(); // 手动添加Filter,比如添加日志Filter,将SQL输出到日志文件 List<Filter> filters = new ArrayList<>(); filters.add(new Slf4jLogFilter()); // 需要log4j或logback支持 datasource.setProxyFilters(filters); return datasource; } }

实操心得:在99%的场景下,使用YAML配置已经完全足够,且更清晰。只有当你需要实现一些非常特定的行为,比如动态修改监控页面参数、集成公司统一的权限框架时,才需要动用Java Config。过度定制会增加维护复杂度。

2.2 传统Servlet/WEB项目的配置

对于非Spring Boot的Web项目(如使用纯Servlet、Spring MVC非Boot方式),需要在web.xml中进行配置。

<?xml version="1.0" encoding="UTF-8"?> <web-app ...> <!-- 1. 配置Druid数据源 (通常通过Spring或其它方式注入,这里省略) --> <!-- 2. 配置监控页面 Servlet --> <servlet> <servlet-name>DruidStatView</servlet-name> <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class> <init-param> <param-name>loginUsername</param-name> <param-value>admin</param-value> </init-param> <init-param> <param-name>loginPassword</param-name> <param-value>admin123</param-value> </init-param> <init-param> <param-name>resetEnable</param-name> <param-value>false</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>DruidStatView</servlet-name> <url-pattern>/druid/*</url-pattern> </servlet-mapping> <!-- 3. 配置Web统计 Filter --> <filter> <filter-name>DruidWebStatFilter</filter-name> <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class> <init-param> <param-name>exclusions</param-name> <param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value> </init-param> <init-param> <param-name>sessionStatEnable</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>DruidWebStatFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>

注意事项:传统项目配置相对繁琐,且数据源需要手动初始化并设置到FilterServlet中(通过DruidStatManagerFacade),步骤更多,容易出错。这也是为什么Spring Boot方案更受欢迎的原因。

3. 监控页面功能全景与实战解读

配置完成后,启动你的应用,访问http://你的应用地址/druid/index.html,输入配置的用户名密码,即可进入Druid监控主页面。这个页面信息量巨大,我们把它拆解成几个核心板块来看。

3.1 数据源概览:连接池的健康仪表盘

这是首页的核心区域,展示连接池的实时运行状态。

关键指标含义解读健康状态参考值异常排查思路
初始化连接数连接池启动时创建的连接数量。等于initial-size配置值。启动后不为配置值,检查配置是否生效。
最小空闲连接连接池中始终保持的最小空闲连接数。等于min-idle配置值。长期远大于此值,可能max-active设置过大或流量低。
最大活跃连接连接池能同时维持的最大连接数。等于max-active配置值。核心指标,接近或等于此值,说明连接池已满。
当前活跃连接正在被业务使用的连接数。应远小于max-active,且波动平稳。持续高位或达到max-active,可能存在连接泄漏或慢SQL。
池中空闲连接创建好但未被使用的连接数。应在min-idle附近波动。长期为0,可能min-idle设置过小或max-active不足。
等待线程数getConnection()时,因无可用连接而进入等待的线程数。理想状态应为0持续大于0,是连接池瓶颈的明确信号,需立即扩容或优化。
SQL执行总数自启动以来执行的SQL总数。-结合QPS看趋势。
事务总数自启动以来开启的事务数。--
连接持有时间分布统计连接从被取用到归还的时间段分布。大部分连接应在“0-1ms”或“1-10ms”区间。如果“>1s”区间占比较高,说明存在长事务或慢查询占用连接。

实战场景分析:假设你看到“当前活跃连接”一直维持在max-active(比如20个),“等待线程数”有5个。这几乎可以肯定发生了连接泄漏。你的排查步骤应该是:

  1. 立即去“SQL”或“慢SQL”页面,按“执行时长”排序,找出最耗时的SQL。
  2. 检查这些SQL是否没有正确关闭ConnectionStatementResultSet。Druid的“连接泄漏检测”功能(需额外开启)可以帮助定位。
  3. 如果慢SQL不多,则可能是业务代码在事务中进行了长时间处理(如循环、远程调用),导致连接占用过久。

3.2 SQL监控与慢SQL清单:定位性能瓶颈的利器

这是Druid监控最强大的功能之一。它记录了每一条执行过的SQL的详细数据。

3.2.1 SQL监控页面解读

进入“SQL监控”页,你会看到一个表格,包含以下关键列:

  • SQL:执行的具体SQL语句(merge-sql开启后,参数会被?替换,相同模式的SQL被合并统计)。
  • 执行数:该SQL被执行的次数。
  • 执行时间:该SQL总耗时。
  • 最慢平均(ms)并发:性能核心指标。
  • 读取行数更新行数:反映了SQL的数据影响范围。
  • 执行+RsHold:执行时间+结果集持有时间。这个值如果远大于“执行时间”,说明程序从数据库取回数据后,在内存中处理了很长时间才关闭结果集,这也是变相的资源占用!

3.2.2 慢SQL页面深度利用

“慢SQL”页面专门展示超过slow-sql-millis阈值的SQL。这里不仅是看个列表,更要会分析。

  1. 关联上下文:点击某条慢SQL的“SQL”内容,可以查看其详细的执行时间分布直方图。结合“最近一段时间”的筛选,可以判断这个慢SQL是突然出现还是历史顽疾。
  2. 对比分析:将“平均耗时”最高的几条SQL,与“执行次数”最高的几条SQL进行对比。有时,一个执行很快但调用量巨大的SQL,其总消耗资源可能超过一个很慢但调用量小的SQL。
  3. 采样详情:Druid会记录慢SQL的样本(通过connectionProperties配置druid.stat.logSlowSql=true;druid.stat.slowSqlMillis=2000),你可以看到具体的参数值和执行时间,这对于调试因特定参数导致的慢查询至关重要。

独家技巧:如何将慢SQL告警接入监控系统?Druid监控页面本身没有告警功能。我的做法是,定期(如每分钟)通过一个健康检查接口(集成DruidStatManagerFacade)或直接读取Druid提供的JSON API(/druid/webapp.json/druid/sql.json)来获取慢SQL列表。然后写一个简单的脚本,如果慢SQL列表不为空,或者某个SQL的平均执行时间超过动态阈值,就触发公司的告警平台(如钉钉、企业微信、Prometheus Alertmanager)。这样就把Druid的监控能力从“被动查看”升级到了“主动告警”。

3.3 Web应用监控与URI监控

这个模块由WebStatFilter提供,它将Web请求与数据库访问关联起来。

  • URL监控:统计每个Web接口(URI)的请求次数、并发、耗时以及该请求执行了多少次SQL。这是一个黄金功能。你可以立刻发现哪个API是“数据库杀手”。比如,一个查询用户详情的API,平均一次请求执行了50条SQL,这很可能遇到了N+1查询问题(在ORM框架如MyBatis、JPA中常见)。
  • Session监控:查看在线用户Session情况。
  • Spring监控(需额外配置):如果你集成了Druid的Spring监控,还可以看到Spring Bean的方法调用统计,进一步细化性能热点。

配置Spring监控(以Spring Boot为例):在配置类中增加一个@Bean

@Bean public ServletRegistrationBean<StatViewServlet> statViewServlet() { // ... 同上 ... // 添加支持Spring监控的参数 initParams.put("spring.datasource.druid.stat-view-servlet.profileEnable", "true"); // 在WebStatFilter里也要开 // 或者更推荐的方式,在YAML中配置 `druid.web-stat-filter.profile-enable: true` return registrationBean; } // 还需要在pom.xml中添加AOP依赖(如果还没有的话) // <dependency> // <groupId>org.springframework.boot</groupId> // <artifactId>spring-boot-starter-aop</artifactId> // </dependency>

配置后,“Web应用”模块下会出现“Spring”子页面,展示Bean方法的执行情况。

4. 生产环境高级调优与安全加固

基础配置只能保证监控页面跑起来,要让它真正在生产环境稳定、安全、高效地发挥作用,还需要做以下几件事。

4.1 性能调优:不让监控本身成为负担

Druid监控在记录SQL和Web请求时,会有一定的性能开销(主要是CPU和内存)。对于超高并发的应用,需要精细调整。

  1. 调整采样率与合并SQL

    spring: datasource: druid: filter: stat: enabled: true merge-sql: true # 必须开启,大幅减少内存占用 slow-sql-millis: 1000 log-slow-sql: true # 关键参数:设置SQL执行时间的日志输出阈值,避免全量记录 # 只有执行时间超过此值的SQL,才会被记录到日志文件(如果配置了LogFilter) connection-properties: druid.stat.slowSqlMillis=1000;druid.stat.logSlowSql=true

    通过merge-sql合并相同模式的SQL,能极大减少内存中维护的监控数据项。

  2. 控制监控数据的内存占用:Druid的监控数据默认保存在内存中。长时间运行后,如果SQL种类极多,可能占用不小内存。可以通过DruidDataSourcesetRemoveAbandoned等相关参数来清理不再使用的监控数据,但更常见的做法是定期重启应用实例(在微服务架构下很自然),或者只关注最近一段时间(如1小时)的数据。

  3. 谨慎开启ProfileprofileEnable参数会记录调用栈,用于定位执行SQL的代码位置,但开销较大。建议只在预发环境或排查具体问题时临时开启。

4.2 安全加固:锁好你的“监控后门”

监控页面泄露的危害不亚于源码泄露。必须严防死守。

  1. 强制访问控制(最重要):如前所述,必须设置login-usernamelogin-password以及allow(IP白名单)。生产环境的白名单通常只允许运维网络跳板机或监控服务器IP访问。
  2. 使用内网域名或路径隐藏:不要使用显而易见的/druid路径,可以改为一个无规律的字符串。同时,确保该服务只在内网暴露,或通过网关/反向代理(如Nginx)增加一层HTTP Basic认证或集成公司单点登录。
  3. 禁用重置功能:再次强调,reset-enable: false
  4. 定期审计访问日志:检查是否有异常IP尝试访问监控页面。

4.3 与现有监控体系集成

大公司通常有统一的监控平台(如Prometheus + Grafana)。我们可以将Druid的指标暴露出去。

  1. 使用Spring Boot Actuator集成:Druid Spring Boot Starter已经提供了对Actuator的集成。添加spring-boot-starter-actuator依赖,并在配置中暴露metrics端点,Druid的相关指标(如jdbc.connections.active)会自动通过/actuator/metrics端点暴露,然后被Prometheus抓取。
    management: endpoints: web: exposure: include: health,info,metrics,prometheus metrics: export: prometheus: enabled: true
  2. 自定义Endpoint:如果需要更定制化的数据(如慢SQL列表),可以自己写一个Spring Boot@Endpoint,在内部调用DruidStatManagerFacade.getInstance().getSqlStatDataMap()等方法获取数据,并以JSON格式返回。

5. 常见问题排查与实战案例

即使配置正确,在实际运行中也可能遇到各种问题。这里记录几个我踩过的坑和解决方案。

5.1 监控页面无法访问(404)

  • 可能原因1:Servlet路径未正确注册。
    • 检查:确认stat-view-servlet.url-pattern的配置。Spring Boot默认是/druid/*。访问时路径必须是http://host:port/context-path/druid/index.html
    • 解决:检查应用日志,看Druid的Servlet是否成功启动。在Spring Boot启动日志中搜索“DruidStatViewServlet”或“druid”。
  • 可能原因2:Spring Security或其它过滤器拦截。
    • 检查:如果你的项目使用了Spring Security,它可能会拦截/druid/*路径。
    • 解决:在Security配置中放行该路径。
      @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/druid/**").permitAll() // 放行druid监控路径 .anyRequest().authenticated() .and().formLogin(); }

5.2 监控页面没有SQL数据或数据不全

  • 可能原因1:Filter配置顺序问题或未生效。
    • 检查statFilter是否被正确添加。在传统web.xml中,Filter顺序有影响。在Spring Boot中,确保spring.datasource.druid.filter.stat.enabled=true
    • 解决:检查数据源初始化日志,确认druid-filter已加载。可以尝试在application.yml中显示指定filters:filters: stat,wall,log4j2(根据你用的日志框架)。
  • 可能原因2:使用了非Druid的数据源。
    • 检查:确保你的应用实际使用的DataSourceDruidDataSource。有时因为依赖冲突或配置错误,可能被替换成了HikariCP或Tomcat JDBC Pool。
    • 解决:在应用启动后,打印一下DataSource的类名:System.out.println(dataSource.getClass().getName());
  • 可能原因3:多数据源配置下监控失效。
    • 场景:使用dynamic-datasource-spring-boot-starter等多数据源组件时,默认的Druid监控可能只监控主数据源。
    • 解决:这需要为每个DruidDataSource实例单独配置并注册到同一个StatViewServlet的监控中,过程较为复杂。通常的变通方案是,只监控最主要的数据源,或者考虑使用更全面的分布式链路追踪工具(如SkyWalking)。

5.3 监控页面打开缓慢或影响应用性能

  • 可能原因:监控数据量过大,渲染耗时。
    • 检查:打开浏览器开发者工具的网络面板,查看加载/druid/index.html后的一系列JSON数据请求(如/druid/webapp.json)的响应时间。
    • 解决
      1. 增加spring.datasource.druid.stat-view-servlet.session-stat-max-count(默认1000)等参数限制,减少历史数据积累。
      2. 如前文所述,开启merge-sql
      3. 考虑在访问量低的时段查看监控,或定期清理应用内存(重启)。

5.4 连接泄漏(Active Connections持续不降)

这是最经典的问题。除了在监控页观察“活跃连接数”是否在请求结束后回落,还可以开启Druid的连接泄漏检测功能。

spring: datasource: druid: # 开启移除长时间未关闭连接的功能 remove-abandoned: true # 连接被占用的超时时间,单位秒(例如300秒) remove-abandoned-timeout: 300 # 输出泄漏连接的日志和堆栈信息 log-abandoned: true

开启后,如果一个连接被获取后超过remove-abandoned-timeout时间仍未归还,Druid会认为它泄漏了,会强制回收并打印警告日志(包含堆栈跟踪),其中就能看到是哪个线程、哪段代码没有正确关闭连接。注意:这个功能有性能开销,且是最后一道防线,根本解决之道还是修复代码中的资源关闭逻辑。

配置并使用Druid监控页面,就像是给你的数据库访问层做了一次全面的“体检”和“实时监护”。它不能直接解决性能问题,但能为你提供最精准的“诊断报告”。从连接池的基本状态到每一条慢SQL的细节,从Web接口的调用链到Spring方法的执行耗时,这些数据是任何性能优化和故障排查的起点。我的习惯是,在项目上线前,一定会把Druid监控配好,并且把监控页面的地址和账号密码记在团队的运维手册里。当线上出现数据库相关告警时,第一个打开的往往就是这个页面。花半小时配置,换来的是线上问题排查效率数倍的提升,这笔投入产出比,绝对是值得的。最后一个小建议,定期(比如每周)花几分钟浏览一下监控页面的“慢SQL”和“URI监控”,也许就能在用户投诉之前,提前发现那些正在悄悄变慢的接口和SQL。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询