关于数据库连接池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住的现象。针对这种问题有两种优化思路:

  1. 提高连接池的复用率。

  2. 增加空闲连接的数量。

通过提高连接复用率来解决这种问题的前提是数据库操作的执行速度够快,监控数据库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数据库连接池性能优化的更多相关文章

  1. 【Java EE 学习 16 上】【dbcp数据库连接池】【c3p0数据库连接池】

    一.回顾之前使用的动态代理的方式实现的数据库连接池: 代码: package day16.utils; import java.io.IOException; import java.lang.ref ...

  2. Apache中配置数据库连接池(数据源)

    由于基于HTTP协议的Web程序是无状态的,因此,在应用程序中使用JDBC时,每次处理客户端请求都会重新建立数据库链接,如果客户端的请求频繁的话,这将会消耗非常多的资源,因此,在Tomcat中提供了数 ...

  3. Jsp中使用数据库连接池.

    原文 Jsp中使用数据库连接池. 1. 在tomcat服务器目录下面的conf中找到一个叫Context.xml的配置文件,在其中加入以下代码 <Resource name="jdbc ...

  4. Vue项目实践中的功能实现与要点

    本贴记录项目实践中,各种功能的实现与技术要点,均有待改进. 路由切换的时候,显示loading动画 目前方案是: 在每个页面都手动装载一个loading组件组件的显示依赖vuex里面的一个值 , 在r ...

  5. 【转】PHP中被忽略的性能优化利器:生成器.md

      PHP  如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明 ...

  6. tomcat项目中配置数据库连接池

    1. 在项目中新建context.xml文件,不要在tomcat服务器的目录中修改context.xml(会对整个服务器生效)..   在web项目的META-INF中存放context.xml 2. ...

  7. 03_dbcp数据源依赖jar包,DBCP中API介绍,不同过dbcp方式使用dbcp数据库连接池,通过配置文件使用dbcp数据库连接池

     DBCP数据源 使用DBCP数据源,需要导入两个jar包 Commons-dbcp.jar:连接池的实现 Common-pool.jar:连接池实现的依赖库. 导入mysql的jar包. DBC ...

  8. DBCP数据库连接池的使用

    DBCP的简单介绍: DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由apache开发通过数据库连接池可以让程序自动管理数据库连接的释放和断开 ...

  9. DBCP数据库连接池的简单使用

    0.DBCP简介      DBCP(DataBase connection pool)数据库连接池是 apache 上的一个Java连接池项目.DBCP通过连接池预先同数据库建立一些连接放在内存中( ...

随机推荐

  1. eclipse preference plugin development store and get

    eclipse plugin development: E:\workspaces\Eclipse_workspace_rcp\.metadata\.plugins\org.eclipse.pde.c ...

  2. 【Babble】批量学习与增量学习、稳定性与可塑性矛盾的乱想

    一.开场白 做机器学习的对这几个词应该比较熟悉了. 最好是拿到全部数据,那就模型慢慢选,参数慢慢调,一轮一轮迭代,总能取得不错效果. 但是面对新来数据,怎么能利用已经训练好的模型,把新的信息加进去? ...

  3. C++11中的右值引用及move语义编程

    C++0x中加入了右值引用,和move函数.右值引用出现之前我们只能用const引用来关联临时对象(右值)(造孽的VS可以用非const引用关联临时对象,请忽略VS),所以我们不能修临时对象的内容,右 ...

  4. 【Visual Studio】VS发布应用未能创建默认证书的问题解决方法

    解决方法:点击你创建的项目 右键> 属性>签名>从存储区选择>选择证书这时候显示无可用证书 ,然后我从文件区选择了一个结果,又出现了第二个问题.提示我“签名时出错: 指定了无效 ...

  5. wamp设置实现本机IP或者局域网访问

    在 httpd.conf 中查找 Allow from 127.0.0.1 Order Deny,Allow Deny from all Allow from 127.0.0.1 在此下面加上 All ...

  6. nginx与apache的参考配置

    nginx与apache是两大最主流的服务器,功能强大,但配置起来也比较麻烦,对于初学者来讲可能有些地方并不完全清楚其作用,这里搜集了一些配置的作用及其使用方法.其中nginx提供了推荐配置,而apa ...

  7. 各种软件的安装教程centos mysql tomcat nginx jenkins jira 等等

    464  Star3,606 Fork 1,460 judasn/Linux-Tutorial 作者: https://github.com/judasn Linux-Tutorial/markdow ...

  8. Kubernetes1.2如何使用iptables

    转:http://blog.csdn.net/horsefoot/article/details/51249161 本次分析的kubernetes版本号:v1.2.1-beta.0. Kubernet ...

  9. 【iCore4 双核心板_ARM】例程六:IWDG看门狗实验——复位ARM

    实验原理: STM32内部包含独立看门狗,通过看门狗可以监控程序远行,程序运行错误时, 未在规定时间内喂狗,自动复位ARM.本实验通过按键按下,停止喂狗,制造程序运行 错误,从而产生复位. 核心代码: ...

  10. <王川自选集第一卷电子书 >读书笔记

    什么叫限定自己能力的边界?就是接受承认一个事实,世界上大多数东西你并不懂,或者一知半解,懂得很肤浅.只有少数东西,由于你可以天天深入的接触,你才有深刻的理解. 购买一个公司的股票,却从未使用其核心产品 ...