一次数据库泄露的解决经历

举报
经典鸡翅 发表于 2022/02/17 22:45:50 2022/02/17
【摘要】 前言 最近用了公司某框架,部署到现场后,现场运维开始维护现场数据,在不断操作的过程中,系统崩溃,查看后台日志,druid连接池已经获取不到连接。于是开始了排查之旅。在此记录。 排查开始 首先后台的报错是这样的。 exception=org.mybatis.spring.MyBatisSystemException:...

前言

最近用了公司某框架,部署到现场后,现场运维开始维护现场数据,在不断操作的过程中,系统崩溃,查看后台日志,druid连接池已经获取不到连接。于是开始了排查之旅。在此记录。

排查开始

首先后台的报错是这样的。


   
  1. exception=org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
  2. ### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 60000, active 10, maxActive 10

第一反应maxActive设置的数量太少了。于是改为100。重新启动,并再次操作大量数据。发现过了一段时间100个也满了。

此时问题不简单了。看来是有代码用了程序连接后,没有释放。

接下来开始确认原因到底是不是有没有释放。

在项目中使用的druid连接池。druid连接池是自带图形化监控工具的。于是开始在项目中配置,启动druid连接池。


   
  1. import com.alibaba.druid.support.http.StatViewServlet;
  2. import com.alibaba.druid.support.http.WebStatFilter;
  3. import org.springframework.boot.web.servlet.FilterRegistrationBean;
  4. import org.springframework.boot.web.servlet.ServletRegistrationBean;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. @Configuration
  8. public class DruidConfig {
  9. @Bean
  10. public ServletRegistrationBean statViewServlet(){
  11. ServletRegistrationBean srb =
  12. new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
  13. //设置控制台管理用户
  14. srb.addInitParameter("loginUsername","root");
  15. srb.addInitParameter("loginPassword","root");
  16. //是否可以重置数据
  17. srb.addInitParameter("resetEnable","false");
  18. return srb;
  19. }
  20. /**
  21. * 注册FilterRegistrationBean
  22. * @return
  23. */
  24. @Bean
  25. public FilterRegistrationBean druidStatFilter() {
  26. FilterRegistrationBean bean = new FilterRegistrationBean(new WebStatFilter());
  27. //添加过滤规则.
  28. bean.addUrlPatterns("/*");
  29. //添加不需要忽略的格式信息.
  30. bean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
  31. return bean;
  32. }
  33. }

重新启动后,访问:localhost:8081/druid。这个路径有人大概会怀疑如果我是通过网关管理的微服务框架,需要通过网关转发访问吗?其实大可不必,通过网关也可以,也是跳转到直接访问的地址。

进入访问地址,跳转到如下的登录界面。

输入刚才在代码中配置的用户名和密码,则可以成功进入。

我们此时要点击数据源,去关注建立的逻辑连接数和关闭的逻辑连接数,关键的指标在这里,如果连接池的开启和关闭是正常的,那么二者的值应该是相等的。

再看看此时的活跃连接数

为0,此时正常,因为还没有进行操作。

接下来开始对之前的操作进行复现,锁定具体的操作。重复之前现场运维所做操作。

通过不断的点击功能,缩小功能范围,最终发现,只要点击左侧树,就会造成逻辑打开连接和逻辑关闭次数不一致。

活跃连接数也到了二者之差。等了几分钟,仍然是这个情况。那么实锤了 这里的代码有问题,连接应该没有释放。那么代码那么多,该如何发现具体代码的位置呢。

接下来配置druid的abandon策略。通过abandon可以强制回收数据库的连接。而活跃的连接被回收则会打印堆栈信息,这是就知道是哪里的sql代码没有释放了。

配置如下:


   
  1. spring:
  2. datasource:
  3. druid:
  4. remove-abandoned: true
  5. remove-abandoned-timeout: 30
  6. log-abandoned: true

重启项目,这个时候durid的监控活跃连接数的功能就可以看到代码信息。

我们点击如下位置:

就会弹出上图的堆栈信息。打马赛克的地方就是代码的详细位置,会标记出来。开发人员去响应的类找到相应代码查看即可。

经过查看代码发现,代码的连接释放存在问题。是自己封装的sql查询类。改为mybatis的写法后,问题解决。

文章来源: blog.csdn.net,作者:经典鸡翅,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/hanqing456/article/details/111878996

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。