前进的问题是:为什么com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable()吃了那么疯狂的执行时间?而且 - 如何解决这个问题?
现在让我告诉你详细信息......
背景 我有Spring MVC java web应用程序,它使用SpringJDBC进行数据访问。数据源配置如下:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.databaseurl}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="testConnectionOnCheckout" value="${c3po.testConnectionOnCheckout}" />
<property name="minPoolSize" value="${c3po.minPoolSize}" />
<property name="maxPoolSize" value="${c3po.maxPoolSize}" />
<property name="checkoutTimeout" value="${c3po.checkoutTimeout}" />
<property name="maxStatementsPerConnection" value="${c3po.maxStatementsPerConnection}" />
</bean>
相关属性:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.databaseurl=jdbc:mysql://localhost:3306/timesheet?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=somepassword
c3po.testConnectionOnCheckout=true
c3po.minPoolSize=5
c3po.maxPoolSize=200
c3po.checkoutTimeout=30000
c3po.maxStatementsPerConnection=50
当前意图: 准备公共可用性申请。所以我创建了非常简单的JMeter测试计划,它使用500个并发线程一次又一次地简单打开应用程序的索引页面。
问题: 是我看到每秒平均请求时间为1700毫秒的appox 140请求性能非常差,这是完全不可接受的。 请注意,在正常情况下无需负载测试,此类请求大约需要6ms。 所以我做了什么 - 我运行jvisualvm,并描述。 它看起来像是com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(),它占用了大部分执行时间。
问题: 为什么com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable()吃了那么疯狂的执行时间?而且 - 如何解决这个问题?
注1:当然我考虑添加更多缓存逻辑以避免调用数据库,但是现在我对c3po&amp; mysql优化。
注意2:我正在运行Windows 7 x64,这不是生产环境(它将是CentOS),但仍然拥有顶级i7英特尔处理器和SSD磁盘我期望更高性能=)
答案 0 :(得分:2)
确保定义preferredTestQuery
,例如SELECT 1
。
来自http://www.mchange.com/projects/c3p0/#preferredTestQuery
preferredTestQuery Default: null Defines the query that will be executed for all connection tests, if the default ConnectionTester (or some other implementation of QueryConnectionTester, or better yet FullQueryConnectionTester) is being used. Defining a preferredTestQuery that will execute quickly in your database may dramatically speed up Connection tests. (If no preferredTestQuery is set, the default ConnectionTester executes a getTables() call on the Connection's DatabaseMetaData. Depending on your database, this may execute more slowly than a "normal" database query.) ....
答案 1 :(得分:1)
所以有一个基本问题:
您有一个最大可达200个连接的池。您有500个并发客户端。如果数据库操作比你的应用程序正在做的其他任何事情要慢得多(并不常见,因为它是网络IO),对于使用数据库连接的每两个客户端线程,将有三个wait(),例如,在awaitAvailable()中。如果这是您的问题的核心,它将独立于池,并且只能通过增加maxPoolSize来解决。
但也存在c3p0特有的问题。 c3p0是比大多数人更“厚”的游泳池,特别是比非常轻巧的Hikari厚。有(我希望)坚固性和可配置性,但潜在的性能成本。在c3p0下,您可以采取以下措施来提高此应用程序的性能:
1)将numHelperThreads设置为高于其默认值3的值,可能为10或20. c3p0将许多维护和测试任务委托给辅助线程池。使用你只需3个帮助线程的负载,这些任务可能会得到备份,从而减慢了Connections的签到速度,从而降低了新客户端的可用性。
2)优化您的测试制度。正如geert3所说,除非你使用最新的c3p0 [c3p0-0.9.5-pre10]和兼容JDBC4的驱动程序,否则你将回到非常慢的测试阶段。您还在结帐时进行测试,这将减慢每个客户端线程的速度。有关建议,请参阅here。
3)设置更大的minPoolSize和/或acquireIncrement。您的游泳池开始时体积很小,只需3个连接就可以增加。在这些设置下需要一些时间才能达到200的完整maxPoolSize(这仍然不足以覆盖您的负载而无需等待)。在过渡期间,当游泳池从小到大时,您的500个客户将花费大量时间等待()。