应用程序级别池(c3p0)和HAProxy用于负载平衡读取副本数据库请求

时间:2013-12-09 21:39:00

标签: proxy load-balancing c3p0 haproxy

为了提高我在Tomcat 7中部署的Java / Spring Web应用程序的性能,我试图将MySQL读取副本用于我已注释为只读的查询。在设置haxproxy服务器之前,我一直在使用c3p0进行连接池,该服务器会将请求加载到读取副本,并且工作正常。我知道这两件事情彼此相互影响,因为每个人都试图集中连接,但是如果我不在应用层使用连接池,那么打开新连接的大量查询会导致使用非常明显的性能Spring的DriverManagerDataSource而不是c3p0的ComboPooledDataSource。

HAProxy设置工作,但设置的超时值(50s)关闭c3p0认为打开的连接,所以我将c3p0上的maxIdleTime设置为40s而不是haproxy的50,以避免在c3p0之前关闭haproxy连接。这实际上工作得很好,但偶尔我仍然会看到一个异常,表明haproxy在c3p0之前杀死了连接。

20:44:14,470 ERROR http-bio-8080-exec-1 transaction.JDBCTransaction:95 - JDBC begin   failed
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 55,267 milliseconds ago.  The     last packet sent successfully to the server was 1 milliseconds ago.
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

我可以看到一些调试消息,其中空闲连接正在被清理,但我想知道为什么c3p0似乎无法清理池中超过40秒的一些连接。

我的配置:

C3P0

<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${db.driver.classname}"/>
    <property name="user" value="${db.username}"/>
    <property name="password" value="${db.password}"/>
    <property name="jdbcUrl" value="${db.url}"/>
    <property name="minPoolSize" value="5"/>
    <property name="maxPoolSize" value="15"/>
    <property name="acquireIncrement" value="5"/>
    <property name="maxIdleTime" value="40"/>
</bean>

HAProxy的

global
    log 127.0.0.1   local0
    maxconn 4096
    user haproxy
    group haproxy
    daemon

defaults
    log global
    mode    http
    option  dontlognull
    retries 3
    option redispatch
    maxconn 2000
    contimeout  5000
    clitimeout  50000
    srvtimeout  50000

listen  MySQL 0.0.0.0:3306
  mode tcp
  balance roundrobin
  server rr1 some.nice.com:3306 maxconn 620
  server rr2 some.cool.com:3306 maxconn 620

提前致谢!

2 个答案:

答案 0 :(得分:1)

我在这里遇到的具体问题是通过增加haproxy中的clitimeout / srvtimeout和c3p0中的maxIdleTime之间的差异以及设置idleConnectionTestPeriod来解决的,因为尽管在c3p0中设置了maxIdleTime,但它不会自动检查空闲连接,除非指定了间隔。

答案 1 :(得分:0)

您是否尝试过指示c3p0对连接进行健康检查? 我有一个类似的问题,连接被关闭,但c3p0认为它仍然是活动的所以我试图使用一个不存在的连接(我没有使用Spring思想)。 添加这些参数对我来说很有用:

hibernate.c3p0.idle_test_period=3000
hibernate.c3p0.timeout=3500
hibernate.c3p0.validate=true
hibernate.c3p0.preferredTestQuery=SELECT 1
hibernate.c3p0.maxConnectionAge=3600
hibernate.c3p0.testConnectionOnCheckin=true
hibernate.c3p0.testConnectionOnCheckout=true
hibernate.c3p0.acquireRetryDelay=1000
hibernate.c3p0.acquireRetryAttempts=30
hibernate.c3p0.acquire_increment=1
hibernate.c3p0.breakAfterAcquireFailure=false