
1. 项目概述为什么我们需要Druid监控页面在Java后端开发里数据库连接池的管理一直是个既基础又关键的问题。项目跑得好好的突然某个接口响应变慢或者数据库连接数飙升导致服务不可用这种问题排查起来往往让人头疼。你可能会去查慢SQL日志或者盯着服务器的CPU和内存但很多时候问题的根源在于连接池本身——连接泄露了没有没有慢SQL在占用连接当前的活跃连接数是多少这就是Druid监控页面出场的时候了。Druid不仅仅是阿里巴巴开源的一个高性能数据库连接池它更是一个自带强大监控能力的“数据库连接管家”。它的监控页面我们常说的stat-view-servlet提供了一个Web可视化界面让你能实时、直观地看到连接池的“心电图”有多少连接正在被使用SQL的执行情况如何有没有Web请求的URI访问统计等等。我见过不少团队Druid依赖是加上了监控页面却懒得配或者配了也不看等到出问题了才临时抱佛脚去查平白浪费了很多排查时间。今天我就以一个踩过不少坑的过来人身份带你从头到尾把Druid监控页面的配置、使用和那些“教科书上不会写”的实战技巧彻底讲明白。2. 核心设计思路Druid监控是如何工作的在动手配置之前我们先花几分钟搞清楚Druid监控的设计逻辑。理解了原理后面配置参数和排查问题才会心里有底。Druid的监控能力核心建立在它的**过滤器链Filter Chain和统计模块Stat**之上。当你通过Druid的数据源DataSource执行一个SQL查询时这个请求会依次经过一系列内置的过滤器。2.1 核心过滤器与数据采集其中与监控最相关的两个过滤器是StatFilter这是统计的“心脏”。它负责采集所有通过Druid连接池执行的SQL语句的执行信息包括执行次数、总耗时、最慢耗时、影响行数等。这些数据是后续监控页面上SQL监控和Web关联等页面的数据来源。WallFilter这是SQL防火墙主要做防SQL注入。虽然不直接提供监控UI的数据但它拦截的非法SQL信息也会在监控页面上有所体现对安全审计很有帮助。这些过滤器采集到的原始数据会被汇总到DruidDataSource内部的统计管理器DruidStatManagerFacade中。这个管理器维护着内存中的统计数据结构。2.2 StatViewServlet数据的HTTP出口光有内存数据还不够我们需要一个方式把它暴露出来。StatViewServlet就是这个HTTP出口。它是一个标准的Java Servlet配置在你的Web应用中比如Spring Boot里通过ServletComponentScan或配置类注册。当你访问监控页面的URL如/druid/index.html时这个Servlet就会接手请求。它的工作流程是接收前端页面一堆HTML/JS/CSS资源Druid已经内置好了的请求。前端JS通过Ajax调用特定的数据接口如/druid/sql.json。StatViewServlet接到数据请求后从DruidStatManagerFacade中获取最新的统计快照。将数据序列化为JSON格式返回给前端页面进行渲染和图表展示。所以整个监控体系可以概括为过滤器采集 - 内存统计 - Servlet暴露 - 前端展示。基于这个理解我们的配置工作其实就是三件事启用正确的过滤器、配置好StatViewServlet、并确保访问安全。3. 手把手配置Spring Boot中的两种主流方式现在进入实操环节。Spring Boot是目前绝对的主流所以这里重点讲在Spring Boot项目中的配置。主要有两种风格基于application.yml/properties的纯配置方式以及基于Java Config的配置类方式。我强烈推荐后者因为它更灵活、更清晰也便于做条件化配置。3.1 基础依赖引入无论哪种方式首先确保你的pom.xml中已经引入了Druid的Spring Boot Starter。注意这里要使用阿里巴巴官方的starter而不是单纯的druid依赖。dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.20/version !-- 请使用当前最新稳定版本 -- /dependency同时你需要一个数据库驱动比如MySQLdependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency3.2 方式一使用application.yml配置快速上手对于简单的项目或想快速验证可以在application.yml中配置。Spring Boot的Druid Starter提供了大量的自动化配置项。spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/your_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: your_username password: your_password druid: # 连接池通用配置 initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000 # 监控配置 stat-view-servlet: enabled: true # 启用StatViewServlet url-pattern: /druid/* # 监控页面的访问路径 login-username: admin # 监控页面登录用户名强烈建议设置 login-password: admin123 # 监控页面登录密码 reset-enable: false # 是否允许在页面上重置所有统计信息生产环境务必设为false allow: 127.0.0.1 # 允许访问的IP为空则允许所有。生产环境务必设置 deny: 192.168.1.100 # 拒绝访问的IP优先级高于allow web-stat-filter: enabled: true # 启用WebStatFilter用于统计Web请求 url-pattern: /* exclusions: *.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/* # 不统计这些静态资源 filter: stat: enabled: true # 启用StatFilter用于SQL统计 log-slow-sql: true # 记录慢SQL slow-sql-millis: 2000 # 慢SQL阈值单位毫秒 wall: enabled: true # 启用SQL防火墙过滤器注意reset-enable这个参数非常关键。如果设为true任何能访问监控页面的人都可以点击“重置”按钮清空所有的历史统计信息。这在生产环境是灾难性的因为你可能正在基于历史数据排查一个间歇性问题。所以生产上一定要设为false。配置完成后启动应用访问http://你的IP:端口/druid/index.html输入上面配置的用户名密码就能看到监控首页了。3.3 方式二使用Java Config配置类推荐生产使用对于正式项目我强烈建议使用配置类。它结构清晰可以方便地注入其他Bean进行更复杂的逻辑控制。首先创建一个配置类例如DruidConfig.javaimport com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; import java.util.Arrays; import java.util.HashMap; import java.util.Map; Configuration public class DruidConfig { // 1. 将application.yml中spring.datasource.druid开头的属性绑定到DataSource Bean ConfigurationProperties(spring.datasource.druid) public DataSource druidDataSource() { return new DruidDataSource(); } // 2. 配置StatViewServlet (监控页面的后端入口) Bean public ServletRegistrationBeanStatViewServlet statViewServlet() { ServletRegistrationBeanStatViewServlet bean new ServletRegistrationBean(new StatViewServlet(), /druid/*); MapString, String initParams new HashMap(); // 登录监控页面的账号密码 initParams.put(loginUsername, admin); initParams.put(loginPassword, your_strong_password_here); // 生产环境要用强密码 // 允许访问的IP多个用逗号分隔。空字符串表示允许所有危险 initParams.put(allow, 127.0.0.1,192.168.1.0/24); // 拒绝访问的IP优先级高于allow // initParams.put(deny, 192.168.1.100); // 是否能够重置数据 initParams.put(resetEnable, false); bean.setInitParameters(initParams); return bean; } // 3. 配置WebStatFilter (用于统计Web请求关联URI和SQL) Bean public FilterRegistrationBeanWebStatFilter webStatFilter() { FilterRegistrationBeanWebStatFilter bean new FilterRegistrationBean(new WebStatFilter()); bean.setUrlPatterns(Arrays.asList(/*)); MapString, String initParams new HashMap(); // 排除对静态资源和监控页面本身的统计 initParams.put(exclusions, *.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*); bean.setInitParameters(initParams); return bean; } }然后在application.yml中只需要保留最基础的数据源连接信息即可监控的细节都在配置类里控制spring: datasource: url: jdbc:mysql://localhost:3306/your_db username: your_username password: your_password driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: # 这里只放连接池参数监控参数移到Java Config initial-size: 5 min-idle: 5 max-active: 20 # ... 其他连接池参数这种方式的好处是你可以很容易地根据Spring Profiles如dev,prod来切换不同的监控配置。比如在开发环境允许所有IP访问且密码简单在生产环境则严格限制IP和使用复杂密码。4. 监控页面详解每个标签页告诉你什么成功登录监控页面后你会看到顶部有一排标签页。每个页面都是一块宝藏我来带你逐一解读。4.1 首页Welcome这里是仪表盘概览展示最重要的几个实时指标数据源DataSource显示你的DruidDataSource名称、数据库类型、驱动版本。连接池活动Pooling Connections这是最需要关注的区域。ActiveCount当前活跃连接数。也就是正在被使用的连接数。如果这个数长期接近MaxActive说明连接池可能不够用了。PoolingCount池中空闲连接数。理想情况下它应该维持在MinIdle附近。MaxActive你设置的最大连接数。WaitThreadCount等待获取连接的线程数。如果这个数大于0说明有SQL在排队等连接是性能瓶颈的明确信号。SQL监控SQL Firewall显示开启的过滤器如stat、wall。4.2 SQL监控SQL Monitor这是排查慢SQL和低效SQL的主战场。页面会列出所有执行过的SQL或一段时间内的并按执行次数、总耗时等排序。SQL具体的SQL语句参数会被替换为?。执行数ExecuteCount该SQL被执行的次数。总耗时TotalTime所有执行次数的耗时总和。最慢MaxTimespan单次执行最慢耗时。直接点这里可以排序快速找到最慢的SQL。影响行数EffectedRowCountUPDATE/INSERT/DELETE影响的行数总和。读取行数FetchRowCountSELECT语句读取的行数总和。实操心得我习惯定期查看这个页面按“最慢”倒序排列。重点关注那些MaxTimespan超过你设定慢SQL阈值比如上面配置的2秒的记录。点击SQL语句有时还能看到详细的执行时间分布在stat日志开启的情况下。4.3 SQL防火墙SQL Firewall如果你配置了WallFilter这里会展示被防火墙拦截的SQL统计。对于防御SQL注入攻击非常有帮助。你可以看到哪些类型的违规操作如syntax_error、none_base_statement被拦截了多少次。4.4 Web应用Web Application这个页面展示了WebStatFilter收集的信息将Web请求URI与SQL执行关联起来。URI应用接收到的请求路径。请求次数RequestCount、并发峰值ConcurrentMax、总耗时等。Jdbc执行数该URI下执行的所有SQL次数总和。Jdbc总耗时该URI下所有SQL执行的总耗时。这个页面的价值在于当发现某个接口变慢时你可以直接在这里找到对应的URI然后结合“URI监控”子页面点击URI可进入查看这个特定接口都执行了哪些SQL从而精准定位是哪个SQL拖慢了整个接口。4.5 连接池Connection Pool这是首页“连接池活动”区域的详细版。以时间线的形式展示了ActiveCount、PoolingCount、WaitThreadCount等关键指标的历史变化曲线。对于分析连接泄露问题特别有用。如果你看到ActiveCount曲线在请求低谷期比如深夜也一直下不来始终保持高位那很可能存在连接没有正确关闭的情况。5. 高级配置与生产环境实战技巧基础的配置只能保证“能用”要想“好用”且“安全”还需要一些进阶操作。5.1 监控数据持久化与日志输出默认情况下Druid的监控数据是存在内存中的应用重启就没了。对于需要长期分析的趋势我们可以配置日志输出。在application.yml中可以开启stat过滤器的日志功能spring: datasource: druid: filter: stat: enabled: true log-slow-sql: true slow-sql-millis: 1000 merge-sql: true # 将相似的SQL仅参数不同合并统计避免列表过长 db-type: mysql # 根据数据库类型优化统计 # 开启Druid内置的日志输出到独立的日志文件 aop-patterns: com.yourpackage.service.* # 监控指定包的Service层 use-global-data-source-stat: true # 使用全局统计同时在logback-spring.xml中可以为Druid单独配置一个Appender将慢SQL或统计日志记录到特定文件方便用日志分析工具如ELK处理。5.2 多数据源下的监控配置现在很多项目会用到多个数据库。如果你使用了像dynamic-datasource-spring-boot-starter这样的多数据源组件配置Druid监控需要一点小技巧。关键点在于StatViewServlet是全局唯一的但它可以收集所有Druid数据源的统计信息。你只需要确保每个数据源都正确配置了filters: stat,wall。在dynamic-datasource的配置中通常如下spring: datasource: dynamic: primary: master datasource: master: url: ... username: ... password: ... driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: filters: stat,wall # 关键为每个数据源启用过滤器 initial-size: 5 max-active: 20 slave: url: ... username: ... password: ... driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: filters: stat,wall # 关键为每个数据源启用过滤器 initial-size: 5 max-active: 10这样配置后访问统一的/druid监控页面你会在“数据源”区域看到多个数据源的列表可以分别查看它们的监控状态。5.3 安全加固绝不暴露在公网这是生产环境的铁律Druid监控页面包含了数据库连接信息、SQL语句、系统线程栈等敏感信息。强密码loginPassword绝对不能是admin、123456这种。IP白名单allow务必配置只允许运维网络或跳板机的IP访问。可以使用IP段如192.168.1.0/24。通过网关或Nginx二次保护不要直接将应用服务的/druid路径暴露到公网。应该通过内部网关、Nginx反向代理并配置额外的认证如OAuth2、JWT或IP限制。禁用Reset再次强调resetEnable: false。6. 常见问题排查与性能调优实录在实际运维中你会遇到各种奇怪的问题。这里记录几个我印象深刻的案例。6.1 问题一监控页面打开空白或JS/CSS加载失败现象能打开登录页登录后页面空白浏览器控制台报404错误找不到.js或.css文件。原因StatViewServlet的url-pattern配置不正确或者被Spring Security等安全框架拦截了静态资源请求。排查检查ServletRegistrationBean的映射路径是否是/druid/*。这个/*很重要它保证了/druid/js/...这样的子路径也能被处理。如果用了Spring Security确保放行了/druid/**路径。Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers(/druid/**).permitAll() // 放行Druid监控所有路径 .anyRequest().authenticated() .and().formLogin(); }检查应用是否有全局的Filter或Interceptor对/druid路径进行了处理可能导致静态资源请求被篡改。6.2 问题二ActiveCount持续很高疑似连接泄露现象在“连接池”监控页面发现ActiveCount曲线即使在业务低峰期也维持在高位PoolingCount空闲连接很少。排查步骤确认泄露在低峰期如凌晨手动触发一次主要的业务接口观察ActiveCount是否会先上升再回落到一个稳定值。如果回落后ActiveCount依然比MinIdle高很多基本可断定泄露。定位泄露点在监控页面“Web应用”或“SQL监控”页面寻找那些Jdbc执行数或执行数异常高但对应的URI或SQL并不常见的记录。这可能是某个被遗忘的循环或定时任务在疯狂创建连接。代码审查检查所有数据库操作代码确保每一个Connection、PreparedStatement、ResultSet都在finally块中或使用try-with-resources语法正确关闭。开启泄露检测在Druid配置中开启连接泄露检测这是一个非常实用的功能。spring: datasource: druid: remove-abandoned: true # 是否移除泄露的连接 remove-abandoned-timeout: 300 # 连接被占用的超时时间秒超过即认为泄露 log-abandoned: true # 输出泄露连接的堆栈日志到日志文件开启后如果一个连接被获取后超过300秒未关闭Druid会认为它泄露了并将其强制回收同时在日志中打印出该连接被获取时的调用栈信息。这个日志是定位泄露代码行的关键。6.3 问题三WaitThreadCount大于0接口超时现象监控首页WaitThreadCount持续大于0甚至很高。前端请求大量超时。原因所有连接都被占用新的请求需要排队等待。根本原因通常是max-active设置过小不足以支撑并发请求。存在慢SQL或事务时间过长长时间占用连接。连接泄露同问题二。调优决策不要盲目调大max-active首先去“SQL监控”页面按“最慢”排序找出并优化慢SQL。解决一个慢SQL比增加100个连接都有效。分析业务场景。如果是报表类查询考虑引入读写分离将慢查询路由到专门的从库。如果业务峰值并发确实很高且SQL已优化到极致再考虑适当增加max-active。同时需要评估数据库服务器本身的连接数上限和性能承受能力。max-active的设置可以参考这个粗糙公式(应用实例数 * max-active) (数据库max_connections * 0.8)要留出余量给其他应用或运维操作。调整max-wait获取连接的最大等待时间。默认是-1表示无限等待。可以设置为一个合理值如5秒超时则抛出异常避免线程被无限挂起快速失败也是一种保护机制。6.4 一个典型的性能调优案例曾经遇到一个后台管理系统在导出大量数据报表时前端频繁超时。通过Druid监控发现现象点击导出时ActiveCount瞬间打满到max-active(20)WaitThreadCount飙升到几十。分析进入“SQL监控”发现一个用于导出数据的SELECT ...语句MaxTimespan高达30秒且ExecuteCount为1说明是单个慢查询。定位在“Web应用”页面找到了对应的导出请求URI确认是这个接口的问题。解决短期为该导出接口增加异步处理请求提交后立即返回后台生成文件并提供下载链接。避免HTTP连接长时间被占用。中期优化该SQL添加缺失的索引将全表扫描改为索引扫描。优化后MaxTimespan降至2秒。长期引入Elasticsearch或ClickHouse等OLAP引擎来承载这类复杂的分析查询与OLTP的MySQL主库解耦。整个过程Druid监控页面提供了从现象连接池打满到根本原因具体慢SQL的完整证据链没有它这种问题的排查效率会低得多。配置和使用Druid监控页面绝不是简单的“配上了就行”。把它当作你观察数据库连接池健康状况的“仪表盘”和“黑匣子”。养成定期查看的习惯尤其是在发布新功能或进行大促活动前后。通过它你不仅能快速定位问题更能深入了解自己应用的数据库访问模式从而做出更科学的架构和性能决策。