一次项目实践中DBCP数据库连接池性能优化
关于数据库连接池DBCP的关注源于刚刚结束的一轮测试,测试内容是衡量某Webserver服务创建用户接口的性能。这是一款典型的tomcat应用,使用的测试工具是Grinder。DBCP作为tomcat服务器常用的数据库连接池,其性能表现直接关乎应用的性能。
1.遇到的问题
当并发量增加到100时,该接口出现瓶颈,此时TPS接近400,如下图。但是服务端CPU和内存等资源并未达到瓶颈,服务器CPU使用率仅为30%,内存使用率为40%。监控到的javaMethod慢方法为incrAppAccountsSize(),该方法的平均响应时间达206ms。该方法的功能是增加app下的用户数,每当我们在该app下创建一个用户,相应app的总用户数就会加1,缓存中响应的数据也会更新。因此该方法涉及数据库和redis的相关操作。
数据库的插入操作通常比较耗时,添加数据库监控后,该接口相关sql语句执行时间如下,可见相关操作的sql语句的平均耗时在20ms左右,然而慢方法的耗时却在200ms左右,因此性能瓶颈不在sql语句。
因此有必要分析下代码执行过程中的堆栈信息,看看慢方法涉及哪些调用。通过jstack dump出现场的堆栈信息如下。
2.数据库连接池DBCP
众所周知,数据库的最大连接数是有限的,服务端与数据库建立连接的过程也是非常消耗资源的,因此高效利用数据库连接是非常必要的。java提供了一套专门与数据库打交道的api--jdbc,基于jdbc开发人员可以实现服务端与数据库端的通信。每次执行数据库操作通常需要经历建立数据库连接、执行数据库操作、断开数据库连接三步。当数据库并发访问量大时或请求频繁时,频繁的建立连接再断开连接会给服务端带来很大的额外开销,严重制约着服务端的性能。
因此,数据库连接需要一套维护策略,基于不同的维护策略出现了很多开源的数据库连接组件,DBCP(DataBase Connection Pool)就是其中一个,也据信是目前性能最好的数据库连接组件。除了DBCP以外还有C3P0,、proxool等也是比较常见的。在一定的维护策略下,数据库连接可以实现复用以及再回收。DBCP的使用很简单引入commons-dbcp依赖,并配置好相关参数即可。DBCP的相关配置参数如下,
maxActive:最大连接数
maxIdle:最大空闲连接数
minIdle:最小空闲连接数
initialSize:初始连接数
minEvictableIdleTimeMillis:对连接进行有效性校验的周期
maxActive的值通常根据自己应用的峰值并发量进行设置,当并发量高于该值后超过的请求会排队等待连接释放;当并发量介于maxIdle和maxActive之间时,使用结束的连接会被立即断开,新来的请求会重新创建连接;当并发量介于minIdle和maxIdle之间时,新来的请求会从连接池充获取一个已经建立的且空闲的连接,迅速实现连接复用。因此通常情况下应用的并发量应该维持在minIdle与maxIdle之间。这样才能保证新来的请求迅速获取一个已经建立的连接。通常情况下initialSize会小于或等于minIdle当服务器重启后服务器会与数据库节点保持initialSize个连接,当并发量超多initialSize后连接数会依次上涨至minIdle、maxIdle和maxActive,当连接空闲时根据回收策略连接会被回收,并最终回落至minIdle。
3.问题分析
结合DBCP以及第一节中利用jstack dump出的堆栈信息,可见服务端一直处于连接断开的过程中。而DBCP建立连接的速度比断开连接快,因此服务端一直卡在资源释放的阶段。服务端的DBCP的相关配置如下:
maxActive:500
maxIdle:50
minIdle:30
initialSize:30
并发访问量为160,在maxIdle和maxActive之间,因此当一个连接使用结束后由于当前连接数大于maxIdle连接无法被复用会被立即断开,新来一个请求也无法获取一个空闲的连接需要重新建立一个新的连接,由于断开连接的响应时间较慢,断开连接都在等待资源的释放,大量的线程出现排队,这样就出现了通过jstack看到的,线程被block住的现象。针对这种问题有两种优化思路:
提高连接池的复用率。
增加空闲连接的数量。
通过提高连接复用率来解决这种问题的前提是数据库操作的执行速度够快,监控数据库sql执行速度在20ms左右,如果多个数据库操作排队对性能影响不大,基于这种思路可以降低maxActive的值。当并发访问量达到上限后不再分配更多的数据库连接,而是等待前一个连接使用结束,由于maxActive与maxIdle的差值变小,因此需要断开的连接的数量变少,这样可以避免由于连接的断开性能较差导致大量线程被block住的情况。将maxActive的值修改为100后,160并发创建用户的性能如下。
慢方法incrAppAccountsSize的响应时间由800多毫秒,减小到80多毫秒,通过jstack抓取现场堆栈信息可以看到有些线程被block在getConnection状态,线程获取连接出现排队,但是由于数据库操作响应时间很快,这种线程被block在getConnection状态的时间并不长。
通过增加空闲连接的数量来也可以改善频繁断开连接所带来的性能问题,由于当前并发量超过了最大空闲连接数,增加空闲连接数可以减少断开连接的数量,提高复用率。但是增加空闲连接的数量会占用宝贵的数据库连接资源,影响服务扩展。将maxIdle大小调整为200后,160并发创建用户的性能如下。
以上数据表明,通过这两种方式可以有效的提高慢方法的响应时间。通过增加空闲连接的数量带来的性能提升优于增加复用率,因为增加空闲连接的数量可以避免排队耗时。单纯的增加maxIdle的值会使得空闲连接的数量增加。并发连接也不会一直维持在maxIdle这个水平,如果当前的并发压力减小了,DBCP本身也有连接回收策略。空闲连接的回收是通过这两个参数来实现的。
minEvictableIdleTimeMillis:空闲连接过期时间
timeBetweenEvictionRunsMillis:空闲连接回收触发周期
当连接池中的空闲连接空闲了minEvictableIdleTimeMillis这么长时间后,该连接会被置为可回收状态。DBCP会按照timeBetweenEvictionRunsMillis的时间进行周期回收。最在没有额外压力的前提下终空闲连接稳定到minIdle水平。
4.总结
数据库连接池的maxIdle和maxActive之间的差值不宜不过大。如果数据库操作响应时间很快的话可以提高连接复用率,但是这么做会出现连接排队的情况。如果数据库操作的响应时间较慢可以增加空闲连接的数量。由于数据库总的连接数是一定的,单个服务的具体数据库连接配额应该根据服务的压力进行调整。
原创文章
禁止其他公众账号转载
一次项目实践中DBCP数据库连接池性能优化的更多相关文章
- 【Java EE 学习 16 上】【dbcp数据库连接池】【c3p0数据库连接池】
一.回顾之前使用的动态代理的方式实现的数据库连接池: 代码: package day16.utils; import java.io.IOException; import java.lang.ref ...
- Apache中配置数据库连接池(数据源)
由于基于HTTP协议的Web程序是无状态的,因此,在应用程序中使用JDBC时,每次处理客户端请求都会重新建立数据库链接,如果客户端的请求频繁的话,这将会消耗非常多的资源,因此,在Tomcat中提供了数 ...
- Jsp中使用数据库连接池.
原文 Jsp中使用数据库连接池. 1. 在tomcat服务器目录下面的conf中找到一个叫Context.xml的配置文件,在其中加入以下代码 <Resource name="jdbc ...
- Vue项目实践中的功能实现与要点
本贴记录项目实践中,各种功能的实现与技术要点,均有待改进. 路由切换的时候,显示loading动画 目前方案是: 在每个页面都手动装载一个loading组件组件的显示依赖vuex里面的一个值 , 在r ...
- 【转】PHP中被忽略的性能优化利器:生成器.md
PHP 如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明 ...
- tomcat项目中配置数据库连接池
1. 在项目中新建context.xml文件,不要在tomcat服务器的目录中修改context.xml(会对整个服务器生效).. 在web项目的META-INF中存放context.xml 2. ...
- 03_dbcp数据源依赖jar包,DBCP中API介绍,不同过dbcp方式使用dbcp数据库连接池,通过配置文件使用dbcp数据库连接池
DBCP数据源 使用DBCP数据源,需要导入两个jar包 Commons-dbcp.jar:连接池的实现 Common-pool.jar:连接池实现的依赖库. 导入mysql的jar包. DBC ...
- DBCP数据库连接池的使用
DBCP的简单介绍: DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由apache开发通过数据库连接池可以让程序自动管理数据库连接的释放和断开 ...
- DBCP数据库连接池的简单使用
0.DBCP简介 DBCP(DataBase connection pool)数据库连接池是 apache 上的一个Java连接池项目.DBCP通过连接池预先同数据库建立一些连接放在内存中( ...
随机推荐
- Kafka:ZK+Kafka+Spark Streaming集群环境搭建(三十):使用flatMapGroupsWithState替换agg
flatMapGroupsWithState的出现解决了什么问题: flatMapGroupsWithState的出现在spark structured streaming原因(从spark.2.2. ...
- http://jqweui.com/
http://jqweui.com/ jQuery WeUI jQuery WeUI 是专为微信公众账号开发而设计的一个简洁而强大的UI库,包含全部WeUI官方的CSS组件,并且额外提供了大量的拓展组 ...
- log4net.Layout.PatternLayout 用 conversion 模式格式化日志事件【翻译】
原文地址 log4net.Layout.PatternLayout,是一个灵活的布局,配置模式字符串. 线程安全.该类型的 Public static 成员对多线程操作是安全的.实例成员不保证线程安全 ...
- 使用SpringBoot入门案例
一.创建项目 二.给根项目UnicomCmp的pom.xml,加入parent节点(spring-boot-starter-parent) <!--Add Spring boot Parent- ...
- Gitbook 命令行工具
1.Gitbook 简介 1.1 Gitbook GitBook 是一个基于 Node.js 开发的命令行工具,使用它可以很方便的管理电子书,GitBook 是目前最流行的开源书籍写作方案. 使用 G ...
- Swift ARC 自动引用计数
1.ARC 引用类型在堆上的内存分配过程中有 8 字节的地址长度用来保存对象的引用计数,堆上的内存并不像栈上那样立即进行回收,系统会定时对堆上的内存进行检查,当某个实例不再被使用时,引用计数会变为 0 ...
- javascript promises powered by BlueBird
什么是promises? 为什么需要promises? 参见: https://promisesaplus.com/ 使用示例: 使用promises之前,代码的编写方式: 使用promises之后: ...
- mongodb复制集Replica Set使用简介
MongoDB高可用 对于MongoDB,可以支持使用单机模式提供服务,但是在实际的生产环境中,单机模式将面临很大的风险,一旦这个数据库服务出现问题,就会导致线上的服务出现错误甚至崩溃.因此,在实际生 ...
- 项目在iOS11上遇到的小问题
iOS11正式版出了这么久了,在忙完新版本开发,写下在iOS11上的一些小问题. 1 App图标不显示 现象:升级到iOS11系统下自己的项目桌面app图标不见了 出现这种情况我还以为自己手动删除 ...
- linux每日命令(4):pwd命令
Linux中用 pwd 命令来查看"当前工作目录"的完整路径. 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录. 在不太确定当前位置时,就会使用pwd来判定当前目录在文 ...