DBCP,C3P0,Tomcat_JDBC 性能及稳定性测试
1.测试环境:
硬件环境:
数据库服务器:2U*8核 8G内存
测试服务器: 2U*8核 6G内存
软件环境:
jdk:
1.6.29
mysql:
5.0.77
mysql_driver:
mysql-connector-java-5.0.8-bin.jar
DBCP:
commons-dbcp-1.4.jar
下载地址: http://commons.apache.org/dbcp/
commons-pool-1.5.6.jar
下载地址: http://commons.apache.org/pool/
C3P0:
c3p0-0.9.1.2.jar
下载地址: http://www.mchange.com/projects/c3p0/index.html
log4j-1.2.8.jar(c3p0需要添加此包)
下载地址: http://logging.apache.org/log4j/
Tomcat_JDBC:
tomcat-jdbc.jar
下载地址: https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html
或者在tomcat安装根目录下的lib目录中直接拿来用之
tomcat-juli.jar
下载地址:(没找到)
在tomcat安装根目录下的bin目录中直接拿来用之
配置信息:
数据库连接超时时间设置为: 10年
数据库支持最大连接数设置为:2000
初始化连接池大小:10
连接至最小活动线程数:10
连接池最大活动线程数:100
其他配置均保持各个连接池的默认配置
2.性能测试:
测试点:
在多线程多任务的条件下,各个连接池获取连接然后马上关闭连接,比较所消耗的时间。
在网上看了好多关于数据库连接池方面的测试,
大多数测试过程中,包括了执行sql语句部分,即,创建连接,执行sql语句,关闭连接,
一开始我也是这样测试,
测试过过程中,发现数据很不稳定, 这几个连接池都是忽快忽慢,
经过思考、分析,个人 觉得这样是不准确的,执行sql语句时,测试已经不是数据库连接池的性能了,
完全是数据库驱动程序(例如mysql_driver )和数据库本身的性能,
数据库连接池负责的仅仅是建立DataSource,获取(从连接池中获取)Connection,关闭(放回到连接池)Connection,
因此,
我在测试时,没有计算初始化连接池(建立DataSource)的时间,而是连接池“获取连接然后马上关闭连接”的时间。
测试结果:
DB POOL | 线程 数量 | 单线程 执行次数 | 消耗时间 (ms) | 开始时间 (ms) | 结束时间 (ms) | 平均消耗 时间(ms) | 平均单条 时间(ms) |
DBCP | 10 | 1000 | 251 | 1328863445815.00 | 1328863446066.00 | 251 | 0.0251 |
252 | 1328863466569.00 | 1328863466821.00 | |||||
251 | 1328863477174.00 | 1328863477425.00 | |||||
254 | 1328863487555.00 | 1328863487809.00 | |||||
247 | 1328863499474.00 | 1328863499721.00 | |||||
C3P0 | 10 | 1000 | 781 | 1328863372064.00 | 1328863372845.00 | 802.8 | 0.08028 |
789 | 1328863385489.00 | 1328863386278.00 | |||||
879 | 1328863401335.00 | 1328863402214.00 | |||||
773 | 1328863413608.00 | 1328863414381.00 | |||||
792 | 1328863424693.00 | 1328863425485.00 | |||||
TomcatJDBC | 10 | 1000 | 191 | 1328863272642.00 | 1328863272833.00 | 191.8 | 0.01918 |
197 | 1328863303126.00 | 1328863303323.00 | |||||
187 | 1328863313262.00 | 1328863313449.00 | |||||
195 | 1328863324253.00 | 1328863324448.00 | |||||
189 | 1328863334700.00 | 1328863334889.00 |
DB POOL | 线程 数量 | 单线程 执行次数 | 消耗时间 (ms) | 开始时间 (ms) | 结束时间 (ms) | 平均消耗 时间(ms) | 平均单条 时间(ms) |
DBCP | 100 | 1000 | 786 | 1328862922748.00 | 1328862923534.00 | 810.4 | 0.008104 |
853 | 1328862939832.00 | 1328862940685.00 | |||||
810 | 1328862955354.00 | 1328862956164.00 | |||||
807 | 1328862981344.00 | 1328862982151.00 | |||||
796 | 1328862994825.00 | 1328862995621.00 | |||||
C3P0 | 100 | 1000 | 2517 | 1328863021884.00 | 1328863024401.00 | 2248.8 | 0.022488 |
2340 | 1328863040949.00 | 1328863043289.00 | |||||
1968 | 1328863075044.00 | 1328863077012.00 | |||||
2256 | 1328863092216.00 | 1328863094472.00 | |||||
2163 | 1328863114138.00 | 1328863116301.00 | |||||
TomcatJDBC | 100 | 1000 | 752 | 1328863155803.00 | 1328863156555.00 | 726 | 0.00726 |
725 | 1328863171617.00 | 1328863172342.00 | |||||
694 | 1328863183983.00 | 1328863184677.00 | |||||
703 | 1328863195628.00 | 1328863196331.00 | |||||
756 | 1328863209798.00 | 1328863210554.00 |
DB POOL | 线程 数量 | 单线程 执行次数 | 消耗时间 (ms) | 开始时间 (ms) | 结束时间 (ms) | 平均消耗 时间(ms) | 平均单条 时间(ms) |
DBCP | 150 | 1000 | 1919 | 1328861533609.00 | 1328861535528.00 | 1854.4 | 0.012363 |
1957 | 1328861551638.00 | 1328861553595.00 | |||||
1869 | 1328861746964.00 | 1328861748833.00 | |||||
1916 | 1328861791533.00 | 1328861793449.00 | |||||
1611 | 1328861832003.00 | 1328861833614.00 | |||||
C3P0 | 150 | 1000 | 2726 | 1328861869415.00 | 1328861872141.00 | 2990.8 | 0.019939 |
2570 | 1328861895349.00 | 1328861897919.00 | |||||
3342 | 1328861912351.00 | 1328861915693.00 | |||||
3218 | 1328861929664.00 | 1328861932882.00 | |||||
3098 | 1328861950163.00 | 1328861953261.00 | |||||
TomcatJDBC | 150 | 1000 | 877 | 1328861974599.00 | 1328861975476.00 | 861 | 0.00574 |
821 | 1328861990969.00 | 1328861991790.00 | |||||
890 | 1328862016507.00 | 1328862017397.00 | |||||
857 | 1328862037077.00 | 1328862037934.00 | |||||
860 | 1328862052490.00 | 1328862053350.00 |
DB POOL | 线程 数量 | 单线程 执行次数 | 消耗时间 (ms) | 开始时间 (ms) | 结束时间 (ms) | 平均消耗 时间(ms) | 平均单条 时间(ms) |
DBCP | 300 | 1000 | 3908 | 1328862516139.00 | 1328862520047.00 | 3851.8 | 0.012839 |
3850 | 1328862408362.00 | 1328862412212.00 | |||||
3939 | 1328862440877.00 | 1328862444816.00 | |||||
3806 | 1328862469116.00 | 1328862472922.00 | |||||
3756 | 1328862495883.00 | 1328862499639.00 | |||||
C3P0 | 300 | 1000 | 6111 | 1328862711585.00 | 1328862717696.00 | 6233.2 | 0.020777 |
5162 | 1328862618669.00 | 1328862623831.00 | |||||
6261 | 1328862638870.00 | 1328862645131.00 | |||||
6832 | 1328862659598.00 | 1328862666430.00 | |||||
6800 | 1328862681808.00 | 1328862688608.00 | |||||
TomcatJDBC | 300 | 1000 | 3458 | 1328862152316.00 | 1328862155774.00 | 3403.8 | 0.011346 |
3376 | 1328862308211.00 | 1328862311587.00 | |||||
3397 | 1328862227685.00 | 1328862231082.00 | |||||
3342 | 1328862261681.00 | 1328862265023.00 | |||||
3446 | 1328862358400.00 | 1328862361846.00 |
结论:
总体性能:TomcatJDBC > DBCP > C3P0
网上好多资料都说C3P0的性能要好于DBCP,从我的测试结果来看并不是这样,也许是我的配置有不正确的地方,
测试时最大的活动线程配置为100,并发为150线程时,TomcatJDBC的优势明显,
也就是当并发超过连接池最大的活动线程数,但并没有超过太多的情况下,TomcatJDBC的优势明显,
我测试的结果都是毫秒级,
对于一个小型的系统,并发压力不大时,选择哪个连接池都没有太大差别,考虑更多的应该是连接池的稳定性。
3.稳定性测试:
测试点:
1.当数据库由于未知原因关闭,重新启动后,连接池是否可以自动重连,无需重启应用服务。
2.应用服务正常,数据库服务正常,但是网络环境异常,导致连接中断,此时连接池中连接处于“半连接”状态,
现象:
在不重启应用服务的情况下, mysql数据库进行重启操作,mysql完全重启后,执行程序,
TomcatJDBC和DBCP并没有自动重连,重复执行查询语句,会一直报异常,重启应用服务后恢复正常
C3P0进行了自动重连,重复执行查询语句,执行正常。
结论:
默认配置条件下,TomcatJDBC和DBCP并没有自动重连机制,查看官方文档,这缺陷可以通过修改配置解决。
另:
连接池重连机制,有2种:
1.同步验证方式:
每次获取连接或关闭连接时,执行一个预定义的验证语句(sql语句),
验证连接池中的连接是否有效,如果验证失败,彻底关闭此连接,
这种方式会导致每次执行数据库操作时都有额外的开销,对性能影响较大。
2.心跳验证方式:
每隔特定的时间进行一次验证,执行一个预定义的验证语句(sql语句),
验证连接池中的连接是否有效,如果验证失败,彻底关闭此连接,
可以根据具体情况,适当的调节验证间隔时间。
这种方式以牺牲较小的性能开销为代价,来保持系统的稳定性。
4.心得
自从tomcat7发布以来,网络上开始出现一个新的连接池的影子,tomcat jdbc,
经过测试,发现tomcat jdbc的性能果然不错,是连接池不二的选择,
本人E文水平有限,没办法把E文翻译的那么优雅,
tomcat jdbc的其他优点,还请看它的官网介绍
https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html
这篇文章详细介绍阐述dbcp与c3p0的一些不足:
Why another connection pool project
重连机制:
不推荐使用同步验证方式,
如果系统架构中,网络环境(应用服务与数据库服务之间)不稳定,硬件环境不稳定,推荐使用心跳验证方式。
如果系统架构中,网络环境和硬件环境都机器稳定,而且对数据库I/O性能要求较高时,可以不进行验证。
转自:http://aub.iteye.com/blog/1404219
DBCP,C3P0,Proxool,BoneCP参数介绍
1 Apache-DBCP:
dataSource: 要连接的 datasource (通常我们不会定义在 server.xml)
defaultAutoCommit: 对于事务是否 autoCommit, 默认值为 true
defaultReadOnly: 对于数据库是否只能读取, 默认值为 false
driverClassName:连接数据库所用的 JDBC Driver Class,
maxActive: 可以从对象池中取出的对象最大个数,为0则表示没有限制,默认为8
maxIdle: 最大等待连接中的数量,设 0 为没有限制 (对象池中对象最大个数)
minIdle:对象池中对象最小个数
maxWait: 最大等待秒数, 单位为 ms, 超过时间会丟出错误信息
password: 登陆数据库所用的密码
url: 连接数据库的 URL
username: 登陆数据库所用的帐号
validationQuery: 验证连接是否成功, SQL SELECT 指令至少要返回一行
removeAbandoned: 是否自我中断, 默认是 false
removeAbandonedTimeout: 几秒后会自我中断, removeAbandoned 必须为 true
logAbandoned: 是否记录中断事件, 默认为 false
minEvictableIdleTimeMillis:大于0 ,进行连接空闲时间判断,或为0,对空闲的连接不进行验证;默认30分钟
timeBetweenEvictionRunsMillis:失效检查线程运行时间间隔,如果小于等于0,不会启动检查线程,默认-1
testOnBorrow:取得对象时是否进行验证,检查对象是否有效,默认为false
testOnReturn:返回对象时是否进行验证,检查对象是否有效,默认为false
testWhileIdle:空闲时是否进行验证,检查对象是否有效,默认为false
initialSize:初始化线程数
2 C3P0:
acquireIncrement: 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
acquireRetryAttempts: 定义在从数据库获取新连接失败后重复尝试的次数。Default: 30
acquireRetryDelay: 两次连接中间隔时间,单位毫秒。Default: 1000
autoCommitOnClose: 连接关闭时默认将所有未提交的操作回滚。Defaul t: false
automaticTestTable: c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。Default: null
breakAfterAcquireFailure: 获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false
checkoutTimeout:当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒。Default: 0
connectionTesterClassName: 通过实现ConnectionTester或QueryConnectionT ester的类来测试连接。类名需制定全路径。Default: com.mchange.v2.c3p0.impl.Def aultConnectionTester
factoryClassLocation: 指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可Default: null
idleConnectionTestPeriod: 每60秒检查所有连接池中的空闲连接。Defaul t: 0
initialPoolSize: 初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3
maxIdleTime: 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0
maxPoolSize: 连接池中保留的最大连接数。Default: 15
maxStatements: JDBC的标准参数,用以控制数据源内加载的PreparedSt atements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0
maxStatementsPerConnection: maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0
numHelperThreads:c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能通过多线程实现多个操作同时被执行。Default: 3
overrideDefaultUser:当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0的数据源时。Default: null
overrideDefaultPassword:与overrideDefaultUser参数对应使用的一个参数。Default: null
password:密码。Default: null
user:用户名。Default: null
preferredTestQuery:定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:测试的表必须在初始数据源的时候就存在。Default: null
propertyCycle:用户修改系统配置参数执行前最多等待300秒。Defaul t: 300
testConnectionOnCheckout:因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都将校验其有效性。建议使用idleConnectio nTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default: false
testConnectionOnCheckin:如果设为true那么在取得连接的同时将校验连接的有效性。Default: false
3 Proxool:
acquireIncrement: 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
fatal-sql-exception : 它是一个逗号分割的信息片段.当一个SQL异常发生时,他的异常信息将与这个信息片段进行比较.如果在片段中存在,那么这个异常将被认为是个致命错误(Fatal SQL Exception ).这种情况下,数据库连接将要被放弃.无论发生什么,这个异常将会被重掷以提供给消费者.用户最好自己配置一个不同的异常来抛出.
fatal-sql-exception-wrapper-class : 正如上面所说,你最好配置一个不同的异常来重掷.利用这个属性,用户可以包装SQLException,使他变成另外一个异常.这个异常或者继承SQLException或者继承字RuntimeException.proxool 自带了2个实现:'org.logicalcobwebs.proxool .FatalSQLException' 和'org.logicalcobweb s.proxool .FatalRuntimeException' .后者更合适.
house-keeping-sleep-time : house keeper 保留线程处于睡眠状态的最长时间,house keeper 的职责就是检查各个连接的状态,并判断是否需要销毁或者创建.
house-keeping-test-sql : 如果发现了空闲的数据库连接.house keeper 将会用这个语句来测试.这个语句最好非常快的被执行.如果没有定义,测试过程将会被忽略。
injectable-connection-interface : 允许proxool 实现被代理的connection对象法.
injectable-statement-interface : 允许proxool 实现被代理的Statement 对象方法.
injectable-prepared-statement-interface : 允许proxool 实现被代理的PreparedS tatement 对象方法.
injectable-callable-statement-interface : 允许proxool 实现被代理的CallableStat ement 对象方法.
jmx : 如果属性为true,就会注册一个消息Bean到jms服务,消息Bean对象名: "Proxool:type=Pool, name=<alias>". 默认值为false.
jmx-agent-id : 一个逗号分隔的JMX代理列表(如使用MbeanServerFactory .fi ndMBeanServer(String agentId)注册的连接池。)这个属性是仅当"jmx"属性设置为"true"才有效。所有注册jmx服务器使用这个属性是不确定的
jndi-name : 数据源的名称
maximum-active-time : 如果housekeeper 检测到某个线程的活动时间大于这个数值.它将会杀掉这个线程.所以确认一下你的服务器的带宽.然后定一个合适的值.默认是5分钟.
maximum-connection-count : 最大的数据库连接数.
maximum-connection-lifetime : 一个线程的最大寿命.
minimum-connection-count : 最小的数据库连接数
overload-without-refusal-lifetime : 这可以帮助我们确定连接池的状态。如果我们已经拒绝了一个连接在这个设定值(毫秒),然后被认为是超载。默认为60秒。
prototype-count : 连接池中可用的连接数量.如果当前的连接池中的连接少于这个数值.新的连接将被建立(假设没有超过最大可用数).例如.我们有3个活动连接2个可用连接,而我们的prototype-count是4,那么数据库连接池将试图建立另外2个连接.这和 minimum-connection-count不同. minimum-connect ion-count把活动的连接也计算在内.prototype-count 是spare connections 的数量.
recently-started-threshold :这可以帮助我们确定连接池的状态,连接数少还是多或超载。只要至少有一个连接已开始在此值(毫秒)内,或者有一些多余的可用连接,那么我们假设连接池是开启的。默认为60秒
simultaneous-build-throttle :这是我们可一次建立的最大连接数。那就是新增的连接请求,但还没有可供使用的连接。由于连接可以使用多线程,在有限的时间之间建立联系从而带来可用连接,但是我们需要通过一些方式确认一些线程并不是立即响应连接请求的,默认是10。
statistics : 连接池使用状况统计。 参数“10s,1m,1d”
statistics-log-level :日志统计跟踪类型。 参数“ERROR”或 “INFO”
test-before-use : 如果为true,在每个连接被测试前都会服务这个连接,如果一个连接失败,那么将被丢弃,另一个连接将会被处理,如果所有连接都失败,一个新的连接将会被建立。否则将会抛出一个SQLException异常。
test-after-use : 如果为true,在每个连接被测试后都会服务这个连接,使其回到连接池中,如果连接失败,那么将被废弃。
trace : 如果为true,那么每个被执行的SQL语句将会在执行期被log记录(DEBUG LEVEL).你也可以注册一个ConnectionListener (参看ProxoolFacade)得到这些信息
4 BoneCP:
acquireIncrement: 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
driveClass:数据库驱动
jdbcUrl:响应驱动的jdbcUrl
username:数据库的用户名
password:数据库的密码
idleConnectionTestPeriod:检查数据库连接池中控线连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0
idleMaxAge:连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0
maxConnectionsPerPartition:每个分区最大的连接数
minConnectionsPerPartition:每个分区最小的连接数
partitionCount:分区数,默认值2,最小1,推荐3-4,视应用而定
acquireIncrement:每次去拿数据库连接的时候一次性要拿几个,默认值:2
statementsCacheSize:缓存prepared statements的大小,默认值:0
releaseHelperThreads:每个分区释放链接助理进程的数量,默认值:3,除非你的一个数据库连接的时间内做了很多工作,不然过多的助理进程会影响你的性能