zoukankan      html  css  js  c++  java
  • 一次数据库泄露的解决经历

    前言

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

    排查开始

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

    exception=org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
    ### 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连接池。

    import com.alibaba.druid.support.http.StatViewServlet;
    import com.alibaba.druid.support.http.WebStatFilter;
    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;
    
    @Configuration
    public class DruidConfig {
    
       @Bean
       public ServletRegistrationBean statViewServlet(){
          ServletRegistrationBean srb =
             new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
          //设置控制台管理用户
          srb.addInitParameter("loginUsername","root");
          srb.addInitParameter("loginPassword","root");
          //是否可以重置数据
          srb.addInitParameter("resetEnable","false");
          return srb;
       }
    
       /**
        * 注册FilterRegistrationBean
        * @return
        */
       @Bean
       public FilterRegistrationBean druidStatFilter() {
          FilterRegistrationBean bean = new FilterRegistrationBean(new WebStatFilter());
          //添加过滤规则.
          bean.addUrlPatterns("/*");
          //添加不需要忽略的格式信息.
          bean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
          return bean;
       }
    }
    

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

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

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

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

    再看看此时的活跃连接数

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

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

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

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

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

    配置如下:

    spring:
      datasource:
        druid:
          remove-abandoned: true
          remove-abandoned-timeout: 30
          log-abandoned: true
    

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

    我们点击如下位置:

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

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

  • 相关阅读:
    Java入门学习路线目录索引(持续更新中)
    关于技术面试,面试官会怎么考察?
    什么是REST以及 RESTful?
    程序猿一般可以从什么平台接私活
    Statement常用的方法回顾
    信息网络安全协会学习总结提交规范
    20155322 2017-2018-1 《信息安全系统设计》第五周 MyBash实现
    20155322 2017-2018-1《信息安全系统设计》第五周 学习总结
    2017-2018-1 20155322 20155327 实验一 开发环境的熟悉
    20155322 2017-2018-1《信息安全系统设计》第四周学习总结
  • 原文地址:https://www.cnblogs.com/jichi/p/13546140.html
Copyright © 2011-2022 走看看