• 0
  • 0
分享
  • 记录一次解决数据库连接池连接泄露BUG——软件测试圈
  • 恬恬圈 2024-03-12 15:07:31 字数 7354 阅读 297 收藏 0

  1 BUG现象

  系统并发请求,系统停滞无法使用,所有接口都是无法与后端进行交互的状态,系统并没有宕机。

  2 BUG的业务流程

  1)插入分数方法 涉及插入表ABCD 加了声明式事务

  2)查询分数方法 涉及表ABCD

  controller() {
  @Transactional
  insertVo();
  selectById();
  }

  3 排查原因

  因为代码不是我写的,一开始我就是怀疑是死锁导致的BUG,然后我用Jconsole,去检测一下死锁,并没有发现死锁,接下来我去Mysql看有没有死锁,结果也没有发现,然后我就懵了,jvm没有锁,mysql也没有锁且没有SQL在执行,为什么请求就会全注阻塞?

  然后我去开始去看这个代码了,我发现他在控制层调用了两个业务层,通常我们只在控制层去做校验去调用一个service啊,然后我就继续看,insertVo插入了很多查询了很多,耗时3秒钟左右,selectById查询了一条SQL,这两个明面上的代码并没有什么加锁或什么飞天操作,想了半天搞不懂为什么。

  然后我开始用排除法,把这些代码一一注释调试一下。我把insertVo注释掉,这个毋庸置疑,那只有一个简单的操作了,就查一表返回,这个绝对是没问题的,然后我把selectById注释掉,居然就好了?selectById只有一条查询SQL啊也没有加锁,这个能解决但是肯定也不是这个原因。

  然后我用druid监控到可使用连接数一直在占用,没有释放,我就去查druid配置,发现配置了。

  initial-size: 20 #初始大小
  min-idle: 20 #最小空闲
  max-active: 40 #最大链接
  max-wait: 10000 #配置获取连接等待超时的时间

  这个配置也没有毛病啊,没办法了我只能去看线程的具体信息了,查出来所有的线程池连接线程都是这样的。

  "pool-6-thread-10" #244 prio=5 os_prio=31 tid=0x00007fe94235f000 nid=0x22803 waiting on condition [0x00000003150ce000]
     java.lang.Thread.State: WAITING (parking)
  at sun.misc.Unsafe.park(Native Method)
  - parking to wait for  <0x00000006c109e090> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
  at com.alibaba.druid.pool.DruidDataSource.takeLast(DruidDataSource.java:2315)
  at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1781)
  at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1494)
  at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5058)
  at com.alibaba.druid.filter.stat.StatFilter.dataSource_getConnection(StatFilter.java:704)
  at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5054)
  at com.alibaba.druid.filter.FilterAdapter.dataSource_getConnection(FilterAdapter.java:2759)
  at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:5054)
  at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1469)
  at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1459)
  at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:83)
  at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
  at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:38)
  at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:104)
  at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:134)
  at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:250)
  at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:258)
  at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:246)
  at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:83)
  at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:184)
  at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:402)
  at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:376)
  at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:572)
  at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:360)
  at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
  at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
  at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
  at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
  at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
  at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
  at com.treach.platform.modules.service.impl.SysLogService$$EnhancerBySpringCGLIB$$36a85251.insert(<generated>)
  at com.treach.platform.log.factory.LogTaskFactory$2.run(LogTaskFactory.java:56)
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
  at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
  at java.lang.Thread.run(Thread.java:750)
     Locked ownable synchronizers:
  - <0x00000007741f0d68> (a java.util.concurrent.ThreadPoolExecutor$Worker)

  是的,连接池连接一直被占用锁住了,为什么会被锁住呢?,也设置了连接等待超时时间啊,然后我怀疑是配置没有生效,写了个代码看看。

  public static void main(String[] args) throws SQLException {
          ConfigurableApplicationContext run = SpringApplication.run(NdCyApplication.class, args);
          DruidDataSource bean = run.getBean(DruidDataSource.class);
          int maxActive = bean.getMaxActive();
          long maxWait = bean.getMaxWait();
          log.info("数据库线程池与数据库最大链接数" + String.valueOf(maxActive));
          log.info("数据库线程池等待链接数超时时间"+String.valueOf(maxWait));
      }

  结果:

  数据库线程池与数据库最大链接数8
  数据库线程池等待链接数超时时间-1

  这个和配置的不一样啊,真的没有生效,然后我又去查为什么没有生效,原来配置类里面有个DataSoure。

  @Bean     //声明其为Bean实例
  @Primary  //在同样的DataSource中,首先使用被标注的DataSource
  @ConfigurationProperties(prefix = "spring.datasource")
  public DruidDataSource dataSource(){
          DruidDataSource datasource = new DruidDataSource();
          List<Filter> filters = new ArrayList<>();
          filters.add(wallFilter);
          filters.add(new StatFilter());
          datasource.setProxyFilters(filters);
          return datasource;
  }

  我们applcation.yaml的配置被覆盖了,druid默认等待链接数超时时间-1,难怪长时间占用连接没有超时。

  4 解决

  把等待连接超时时间等设置上:

  @Bean     //声明其为Bean实例
  @Primary  //在同样的DataSource中,首先使用被标注的DataSource
  @ConfigurationProperties(prefix = "spring.datasource")
  public DruidDataSource dataSource(){
          DruidDataSource datasource = new DruidDataSource();
          datasource.setInitialSize(20);
          datasource.setMaxActive(80);
          datasource.setMaxWait(5000);
          List<Filter> filters = new ArrayList<>();
          filters.add(wallFilter);
          filters.add(new StatFilter());
          datasource.setProxyFilters(filters);
          return datasource;
  }

  成功!


作者:isyues    

来源:http://www.51testing.com/html/41/n-7797341.html

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 简介软件测试是一个快速发展的职业领域,随着信息技术的不断发展和应用,软件测试的重要性也越来越受到重视。软件测试职业是指专门从事软件测试工作的人员,他们负责对软件系统进行全面、深入、有效的测试,发现和解决软件中的缺陷和错误,提高软件的质量和可靠性。软件测试职业的发展前景广阔,随着信息技术的不断发展和应用,软件测试职业的需求也越来越大。软件测试职业可以在各种行业和领域中得到广泛的应用,包括互联网、金融、医疗、教育、制造等领域。软件测试职业的薪资待遇也较为优厚,具有一定的职业晋升空间和发展前景。下面是关于软件测试的详细介绍和内容。软件测试是指在软件开发过程中,通过对软件系统进行各种测试活动,发现和纠...
            0 0 692
            分享
          •   应用场景  测试场景中,我们会先做一些SMOKE测试,以便先了解一下基本的测试是否通过,如在API测试中,先验证返回的Json文件一样,在没有具体到细节时,我们会先了解返回的Json文件是否符合正确的Json格式,以及某次字段数据类型、格式是不是和预先定义的相匹配。  今天就介绍一下Rest-Assured支持的Json schema-validator一次验证整个回应的Json文件。  测试框架: Java + Rest-Assured  语言: Java  IDE: Intellij IDEA  项目类型: Maven  公共API 地址:  https://api.data.gov....
            12 12 1548
            分享
          • 又属于一篇普及文,希望自己在被各种技术吸引的同时,能时常来整理和总结软件测试最基本的知识。从刚工作时接触的第一个缺陷管理工具禅道,到redmine、JIRA、bugzilla,再到现在的QC,当然还有其它种的开源的或商业的缺陷管理工具,它们的本质是一样的,就是来管理缺陷的生命周期。其实,你理解任意的一款工具,其它的工具也一定能无师自通。这不谈某款工具,单把它本质的一些东西抽离出来与大家分享。Bug的属性Bug重现环境这个应该是我们重现bug的一个前提,如果没有这个前提,我们可能会无法重现问题,或者跟本就无从下手。操作系统这个是一般软件运行的一大前提,基本上所有的软件都依赖于操作系统之上的,对于...
            0 0 1149
            分享
          •   字节跳动员工李蓓最近颇感不安,担心随时被裁的焦虑情绪一直笼罩着她。  最近,她眼睁睁看着同事们一个一个地被裁离开了公司。就在一个月前,她也接到了公司的PIP(绩效管理提升计划)。该计划主要针对绩效考核未达标的员工,根据以往的经验,接到PIP就意味着离被辞退不远了,因为鲜有人能顺利完成这项计划。  据了解,字节跳动内部每年有两次考核,一般为3月和9月,考核方式借鉴Google的OKR+360模式,公司内部考核一共有八级,从低到高为F、I、M-、M、M+、E、E+、O,按比例分布,对应年终奖和月薪百分比的涨幅。  事实上,大厂每到年底都会有所谓的人员优化措施,但这一次,让李蓓倍感焦虑的原因在于...
            0 0 725
            分享
          •   我是如何走上测试之路的  我是统招本,专业是计算机信息系统和信息管理,大四在一家事业单位(就不说名字了)实习做Android开发的,等我快毕业的时候,单位明确告诉我不会转正。当然了,我是很清楚的,没有背景,也没有关系,学历也只是本科,想要进去还是很难得。但是也有一丝丝的沮丧,但也就是一点。  大学毕业后,我找了一个互联网公司,开始了我的Android应用开发之路,也就是半年的时间,公司业务扩展比较快,APP的用户量变得比较大了,APP的一些问题开始凸显出来,公司就准备招聘测试。而且要求还挺高的,但是还是要有公司内容的老人去带着业务、讲技术什么的,那时候这个活就交给我了:我当时就很纳闷,我自...
            0 0 316
            分享
      • 51testing软件测试圈微信