直接在生产环境启用sql耗时监控的关键是不扰动业务、不引入风险、能快速验证;druid的filter机制天然适配,需确保statfilter启用且配置正确(如mergesql=true、slowsqlmillis=500),结合自定义filter补充场景需求,灰度上线并对接可观测体系。

直接在生产环境启用SQL耗时监控,关键不是“加功能”,而是“不扰动业务、不引入风险、能快速验证”。Druid的Filter机制天然适合这个目标——它基于代理拦截,不修改业务代码,不侵入JDBC调用链,且支持热加载和细粒度开关。
确认基础监控已启用且稳定
别跳过这一步。很多线上问题源于StatFilter本身配置异常或未生效:
- 确保druid.stat.mergeSql=true(默认false),否则同一条SQL带不同参数会被视为多条,统计失真
- 设置合理慢SQL阈值:druid.stat.slowSqlMillis=500(根据业务RT P95动态调整,非固定1秒)
- 开启日志但限制级别:druid.stat.logSlowSql=true + druid.stat.slowSqlLogLevel=WARN,避免INFO刷屏
- 验证StatFilter是否已注册:检查DruidDataSource.getProxyFilters()列表中含StatFilter实例
用自定义Filter补充StatFilter的盲区
StatFilter统计全局指标,但无法满足特定场景需求,比如只监控某几张核心表、排除健康检查SQL、或注入traceId。这时需轻量级自定义Filter:
- 继承FilterEventAdapter(比FilterAdapter更专注事件回调,避免重写无关方法)
- 只覆盖statementExecuteAfter和statement_executeErrorAfter两个方法
- 在方法内快速判断SQL特征(如sql.toLowerCase().startsWith("select from order")),命中才记录耗时与上下文
- 避免在Filter中做IO操作(如打日志到文件、调远程服务),改用内存队列+异步线程批量上报
灰度上线与效果验证
监控本身也是服务,必须可灰度、可观测、可回滚:
- 通过JVM参数控制开关:-Ddruid.sql.monitor.enabled=true,代码中读取并决定是否将自定义Filter加入dataSource.setProxyFilters()
- 上线后立即访问Druid监控页(/druid/sql.html),确认新SQL条目出现,且ExecuteTime列有数值
- 对比同一SQL在监控页的LastTime与应用日志中的实际耗时,偏差应<5ms(排除网络与序列化开销)
- 观察GC频率与线程CPU占用,确认Filter未引发性能抖动(尤其注意避免在Filter中创建大量临时对象)
对接现有可观测体系
监控数据孤岛等于没有监控。把Druid指标变成SRE团队能用的信号:
- 通过DruidStatManagerFacade.getInstance().getSqlStatDataList()定时拉取,转换为Prometheus格式暴露/metrics端点
- 对高频慢SQL自动触发告警:如“SELECT * FROM user WHERE id = ?近5分钟平均耗时>800ms”
- 将statement.getConnectionProxy().getId()与应用TraceID绑定,实现SQL耗时在全链路追踪中可下钻
- 禁用druid.stat.useGlobalDataSourceStat=false,避免多个数据源指标混杂,便于分库分表场景定位











