• 【数据库】数据库连接池导致系统吞吐量上不去-复盘


    在实际的开发中,我们会使用数据库连接池,但是如果不能很好的理解其中的含义,那么就可以出现生产事故。

    HikariPool-1 - Connection is not available, request timed out after 30001ms.
    
    • 1

    当系统的调用量上去,就出现大量这样的连接失败,分析发现其实就是连接池使用的默认的。

    案例

    CREATE TABLE `user` (
      `id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
      `login_name` varchar(50) NOT NULL COMMENT '登陆名',
      `name` varchar(50) DEFAULT NULL COMMENT '昵称',
      `password` char(32) NOT NULL COMMENT '密码',
      `pass_word` varchar(255) DEFAULT NULL,
      UNIQUE KEY `login_name_unique` (`login_name`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @RequestMapping(path = "/hiii",method = RequestMethod.GET)
        public String hi() {
            userService.saveUserDb();
            return "hi UserService";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    @Entity
    @Data
    @Table(name = "user")
    public class User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        private String loginName;
    
        private String password;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
        public void saveUserDb() {
            User user = new User();
            user.setLoginName(Math.random()+System.currentTimeMillis()+"");
            user.setPassword(Math.random()+System.currentTimeMillis()+"");
            user.setName("qxlx"+System.currentTimeMillis());
            try {
                userRepository.save(user);
                TimeUnit.MILLISECONDS.sleep(30000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    @Repository
    public interface UserRepository extends JpaRepository<User, Long> {
    }
    
    • 1
    • 2
    • 3

    使用wrk进行压测。

    ./wrk -t100 -c100 -d60s --latency http://localhost:8088/hiii
    
    • 1

    在这里插入图片描述

    之后就出现大量的故障 error。发现复现这个问题。

    java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30001ms.
    	at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:695) ~[HikariCP-3.4.5.jar:na]
    	at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:197) ~[HikariCP-3.4.5.jar:na]
    	at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:162) ~[HikariCP-3.4.5.jar:na]
    	at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:128) ~[HikariCP-3.4.5.jar:na]
    	at org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:38) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:104) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:134) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:259) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:267) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:246) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:83) ~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
    	at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:184) ~[spring-orm-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:402) ~[spring-orm-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:400) ~[spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373) ~[spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:573) ~[spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:361) ~[spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118) ~[spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178) ~[spring-data-jpa-2.3.1.RELEASE.jar:2.3.1.RELEASE]
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at com.sun.proxy.$Proxy86.save(Unknown Source) ~[na:na]
    	at sun.reflect.GeneratedMethodAccessor123.invoke(Unknown Source) ~[na:na]
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_202]
    	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_202]
    	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:205) ~[spring-aop-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at com.sun.proxy.$Proxy63.save(Unknown Source) ~[na:na]
    	at com.qxlx.spingboot.service.UserService.saveUserDb(UserService.java:27) ~[classes/:na]
    	at com.qxlx.spingboot.controller.HelloWorldController.hi(HelloWorldController.java:21) ~[classes/:na]
    	at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown Source) ~[na:na]
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_202]
    	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_202]
    	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    默认是使用10个线程池,但是每个任务处理时间是30S左右,100个线程任务,肯定执行不完,所以就导致有90个线程等待连接,接着超过固定的时间30S,就跑出异常。

    在这里插入图片描述
    这里就是如何查看,数据库连接池是设置的,可以通过jconslone,进行查看。

        hikari:
          register-mbeans: true
          maximum-pool-size: 150
          minimum-idle: 25
    
    • 1
    • 2
    • 3
    • 4

    进行配置调整连接池大小。一定要进行查看是否生效。

    在这里插入图片描述

    调整之后用同样的压测参数,发现没有问题。
    在这里插入图片描述

    原理

    在这里插入图片描述

    连接池的整体流程,
    1.首次检查又没有空闲连接,如果有直接使用。
    2.如果没有,查看目前连接池又没有达到所允许的最大连接数,没有就新建一个数据库连接,否则就等待一定时间的timeout等待别的连接释放。
    3.如果超过一定时间的timeout,都没有释放,数据库连接建立失败。
    Spring boot 2.0 默认使用HikariCp 连接池。

    具体可以看如下两篇文章。
    https://mp.weixin.qq.com/s/4ty3MrsymRsdz0BSB_lfyw
    https://mp.weixin.qq.com/s/xM4r8fHQAwmgpX02F51N2A

    小结

    小结一下,对于连接池参数问题建议做到以下几点:
    做好配置确保可以实时监控,确保自己的配置是生效的。
    进行压测确保配置参数符合预期效果。
    配置连接参数要确保留有一半的余量,并保证我们的监控工具能够在剩余不到一半的情况下发出预警。

    所以配置还是有一定的讲究,需要结合业务流量、底层资源的使用情况进行合理分配,过小可能导致吞吐量上不去,过大可能在流量高峰期压垮数据库。

  • 相关阅读:
    java计算机毕业设计交通事故档案管理系统源码+数据库+系统+lw文档+mybatis+运行部署
    (附源码)计算机毕业设计ssm 基于java的仓库管理系统
    【自定义类实现对象的拷贝 Objective-C语言】
    JVM运行数据区深度解析
    Kubernetes组件和架构简介
    ubuntu16 ARM 4G双网卡的上网配置
    微软如何打造数字零售力航母系列科普02 --- 微软低代码应用平台加速企业创新 - 解放企业数字零售力
    湖南工商大学------函数及其应用
    用较新版本的Android Studio Chipmunk编译旧版本的Android 21的Sample
    HTML CSS大学生期末网页大作业 DW个人网页设计 人物介绍 历史人物岳飞介绍
  • 原文地址:https://blog.csdn.net/jia970426/article/details/133757742