从JDBC池连接时,HAProxy,客户端超时

我有一个Web应用程序(Tomcat的/hibernate/ DBCP 1.4),运行MySQL的查询,这对一定的负载工作正常,说50秒的查询。 当我通过HAProxy(仍然只使用一个数据库)传递相同的中等负载时,我得到一个失败,也许每500个查询就有一个失败。 我的应用报告:

Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet successfully received from the server was 196,898 milliseconds ago. The last packet sent successfully to the server was 0 milliseconds ago. at sun.reflect.GeneratedConstructorAccessor210.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.mysql.jdbc.Util.handleNewInstance(Util.java:411) at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1117) at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3567) ... Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost. at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3017) ... 

同时HAProxy日志显示了很多条目,如:

 27] mysql mysql/db03 0/0/34605 2364382 cD 3/3/3/3/0 0/0 Oct 15 15:43:12 localhost haproxy[3141]: 127.0.0.1:35500 [15/Oct/2012:15:42:50.0 

“cD”显然表示客户端超时状态。 所以,虽然我的webapp是说HAProxy拒绝接受新的连接,HAProxy是说我的webapp不接受数据回来。

我不包括我的HAProxyconfiguration,因为我已经尝试了许多不同的参数值,基本上是相同的结果。 特别是,我已经在全局和服务器部分中将maxconn设置为高值和低值,并且在统计数据中总是发生的事情是最大会话数不超过7个。我的JDBC池大小也很高。

通常可以一起使用JDBC池和HAProxy池吗? 以前有人遇到这种问题吗?

我有一个关于如何解决这个问题的想法,即在每个查询之前发送一个“validation查询”。 但是这里有一定的开销,我仍然想知道为什么我的web应用程序直接进入MySQL时成功了,但是在通过HAProxy时却丢失了连接。

我怎样才能进一步debugging,获得更多的信息,而不仅仅是“cD”? 我尝试在debugging模式下运行HAProxy,但似乎没有透露更多信息。


更新 – 星期五Jan 1 11:49:28 ICT 2013(回复JimB)

从haproxy获取更多信息的唯一方法是使用show sessshow sess <id>命令来观察每个tcp连接的状态

以下是有关会议的一些信息:

0x31f4310: proto=tcpv4 src=192.168.3.40:60401 fe=FE_mysql be=BE_mysql srv=mysql3 ts=08 age=1m2s calls=2 rq[f=909202h,l=0,an=00h,rx=13s,wx=,ax=] rp[f=109202h,l=0,an=00h,rx=13s,wx=,ax=] s0=[7,18h,fd=0,ex=] s1=[7,18h,fd=1,ex=] exp=13s

0x31fca50: proto=tcpv4 src=192.168.3.40:60423 fe=FE_mysql be=BE_mysql srv=mysql1 ts=08 age=2s calls=2 rq[f=909202h,l=0,an=00h,rx=1m13s,wx=,ax=] rp[f=109202h,l=0,an=00h,rx=1m13s,wx=,ax=] s0=[7,18h,fd=9,ex=] s1=[7,18h,fd=12,ex=] exp=1m13s

Haproxy有一个10秒的默认超时时间(示例configuration有50秒,我认为)。 我不熟悉JDBC,但从Tomcat的文档,有一个设置minEvictableIdleTimeMillis ,这将从池中驱逐空闲连接,默认为60秒,可能高达65秒,因为timeBetweenEvictionRunsMillis是5秒默认。 基本上,您需要确保您的haproxy超时时间足够长,以解决池中的这些空闲连接。

我已经增加了timeout client 75秒,现在上面的错误似乎发生比以前less:

debugging:通信链接失败

从服务器成功收到的最后一个数据包是145,255毫秒前。 成功发送给服务器的最后一个数据包是10毫秒前。

我还想指出的是:除了上面的,还有一些这样的错误:

通信链路故障成功发送到服务器的最后一个数据包是0毫秒前。 驱动程序尚未收到来自服务器的任何数据包。

在服务器端,有时我看到sD标志处于断开状态:

haproxy[15770]: 192.168.3.40:56944 [04/Jan/2013:11:06:55.895] FE_mysql BE_mysql/mysql1 0/0/77153 1954480 sD 1/1/1/1/0 0/0

timeout server也被设置为75秒。

另一种方法是使用testWhileIdlevalildationQuery来保持连接处于活动状态,因为每隔几秒钟几个数据包stream量也可能会缓解这个问题。

如果没有其他方法,我会build议开发人员尝试这些选项。

从haproxy获取更多信息的唯一方法是使用show sessshow sess <id>命令定期查看每个tcp连接的状态,但我不确定是否会再获得更多信息有用的信息。

cD终止状态是您所拥有的最有用的信息。 这意味着什么与客户build立的联系已经超时了。 这在haproxy中通过configuration中的timeout client参数进行控制,全局设置,或者在frontent或listen部分。

你说你没有看到并发连接超过7,而这个日志条目显示,只有3个连接时发生了故障,所以我怀疑你有连接限制问题(甚至在haproxy的控制之外)。

所以看起来像是在发生,有时候池会增加一个新的连接,处理一些查询,然后闲置。 当这个连接的空闲时间超过haproxy中的timeout client设置时,haproxy将自行终止连接。 下次从池中使用连接时,会出现上述错误。

Haproxy有一个10秒的默认超时时间(示例configuration有50秒,我认为)。 我不熟悉JDBC,但从Tomcat的文档,有一个设置minEvictableIdleTimeMillis ,这将从池中驱逐空闲连接,默认为60秒,可能高达65秒,因为timeBetweenEvictionRunsMillis是5秒默认。 基本上,您需要确保您的haproxy超时时间足够长,以解决池中的这些空闲连接。

另一种方法是使用testWhileIdlevalildationQuery来保持连接处于活动状态,因为每隔几秒钟几个数据包stream量也可能会缓解这个问题。

[编辑]回复@ quanta的附加信息:

即使haproxy超时现在是75秒,你肯定仍然会得到会话超时。 在我不知道的JDBC连接的整个生命周期中,可能会有一些附加操作。 由于这种types的服务所需的连接非常less,因此将超时增加到非常高的时间(大约一小时或更长)也没有任何问题。 如果JDBC池真的在释放旧连接时遇到问题,这只会掩盖问题,但也可能是一个简单的解决方法。