从Linux到MS SQL Server 2008的JDBC连接在40秒后超时

问题描述

|| [查看底部的更新] 我正在使用JDBC从运行带有2.6.32-32服务器内核的Ubuntu 10.04 LTS的计算机上的Windows 2008 R2计算机上的SQL Server 2008 R2运行语句。我正在使用适用于Ubuntu的当前Sun Java 6构建版本(sun-java6-jdk 6.24-1build0.10.04.1)和MS \的当前JDBC 3.0驱动程序(sqljdbc_3.0.1301.101_enu)。 当一条语句完成的时间超过40秒且不返回ResultSet时(例如\'stmt.executeUpdate(\“ SELECT * INTO BAR FROM FOO \”)\'),该程序将终止连接重置:
Exception in thread \"main\" com.microsoft.sqlserver.jdbc.SQLServerException: Connection reset
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1352)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1339)
    at com.microsoft.sqlserver.jdbc.TDSChannel.read(IOBuffer.java:1654)
    at com.microsoft.sqlserver.jdbc.TDSReader.readPacket(IOBuffer.java:3694)
    at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:5022)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.doExecuteStatement(SQLServerStatement.java:773)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement$StmtExecCmd.doExecute(SQLServerStatement.java:676)
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4575)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1400)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:179)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:154)
    at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeUpdate(SQLServerStatement.java:633)
    at TestTimeout.main(TestTimeout.java:42)
如果我的陈述式确实传回ResultSet(例如\'ResultSet res = stmt.executeQuery(\“ SELECT * FROM FOO \”)\'),则连线不会逾时。 当我在Win2003R2上运行相同的语句而不针对SQL2005中的数据库副本返回ResultSet时,该语句完成且未在40秒时重置连接。 我启用了日志记录功能,并比较了以未完成的SQL2008R2语句结尾的SQL2005语句的日志,它们与2008年查询中的连接重置消息一样,都是逐行等效的。看到在12:54:47 PM的那一行:
Jun 6,2011 12:54:07 PM com.microsoft.sqlserver.jdbc.TDSCommand onRequestComplete
FINEST: TDSCommand@7ac2b2f6 (SQLServerStatement:1 executeXXX): request complete
Jun 6,2011 12:54:07 PM com.microsoft.sqlserver.jdbc.TDSCommand startResponse
FINEST: TDSCommand@7ac2b2f6 (SQLServerStatement:1 executeXXX): Reading response...
Jun 6,2011 12:54:47 PM com.microsoft.sqlserver.jdbc.TDSChannel read
FINE: TDSChannel (ConnectionID:1) read failed:Connection reset
Jun 6,2011 12:54:47 PM com.microsoft.sqlserver.jdbc.SQLServerException logException
FINE: *** SQLException:ConnectionID:1 com.microsoft.sqlserver.jdbc.SQLServerException: Connection reset Connection reset
Jun 6,2011 12:54:47 PM com.microsoft.sqlserver.jdbc.SQLServerException logException
FINE: com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1352)com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1339)com.microsoft.sqlserver.jdbc.TDSChannel.read(IOBuffer.java:1654)com.microsoft.sqlserver.jdbc.TDSReader.readPacket(IOBuffer.java:3694)com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:5022)com.microsoft.sqlserver.jdbc.SQLServerStatement.doExecuteStatement(SQLServerStatement.java:773)com.microsoft.sqlserver.jdbc.SQLServerStatement$StmtExecCmd.doExecute(SQLServerStatement.java:676)com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:4575)com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1400)com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:179)com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:154)com.microsoft.sqlserver.jdbc.SQLServerStatement.executeUpdate(SQLServerStatement.java:633)TestTimeout.main(TestTimeout.java:42)
[...]
这是针对2005数据库的语句中对应的行:
Jun 6,2011 2:02:20 PM com.microsoft.sqlserver.jdbc.TDSCommand onRequestComplete
FINEST: TDSCommand@4737371 (SQLServerStatement:1 executeXXX): request complete
Jun 6,2011 2:02:20 PM com.microsoft.sqlserver.jdbc.TDSCommand startResponse
FINEST: TDSCommand@4737371 (SQLServerStatement:1 executeXXX): Reading response...
Jun 6,2011 2:02:57 PM com.microsoft.sqlserver.jdbc.TDSChannel logPacket
FINEST: /XXX.XXX.XXX.XXX:60091 SPID:73 TDSReader@6 (ConnectionID:1) received Packet:1 (13 bytes)
XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX   .....I..........
XX XX XX XX XX                                    .....
Jun 6,2011 2:02:57 PM com.microsoft.sqlserver.jdbc.TDSCommand onResponseEOM
FINEST: TDSCommand@4737371 (SQLServerStatement:1 executeXXX): disabling interrupts
Jun 6,2011 2:02:57 PM com.microsoft.sqlserver.jdbc.TDSReader nextPacket
FINEST: TDSReader@6 (ConnectionID:1) Moving to next packet -- unlinking consumed packet
Jun 6,2011 2:02:57 PM com.microsoft.sqlserver.jdbc.TDSParser parse
FINEST: TDSReader@6 (ConnectionID:1): getNextResult: Processing TDS_DONE (0xFD)
[...] 
我使用tcpdump捕获了SQL Server主机和Linux主机之间的所有流量以及所有ICMP流量,并且我注意到,在语句开始执行30秒后,2008和2005服务器都向Linux发送了一个TCP保持活动数据包。 Linux主机使用ACK确认来自2005服务器的保持活动状态,但在连接到2008服务器时,Linux主机不发送ACK,并且2008服务器在重设保持活动状态之前重传9次(每秒一次)。连接(因此需要40秒的时间直到超时)。现在,我注意到Win2003 / SQL2005和Win2008R2 / SQL2008R2主机传输的保持活动数据包之间存在差异:较新的OS使用窗口大小为66560的TCP窗口缩放。所以现在我想知道TCP窗口大小> 65535导致Linux计算机上的iptables或tcp / ip堆栈静默忽略该数据包。但是随后连接中的其他数据包也具有缩放的窗口大小66560,并且Linux服务器会确认它们。日志文件中没有任何内容指示这些数据包被丢弃或引起任何类型的问题。 最后一点:在解决这个问题的过程中,由于更新,我们不得不重启Linux服务器几次,并且两次连接都没有超时一两天。 所以我很困惑,我希望你们中的一个可能对我有所帮助。 更新资料 我发现可以通过在Linux服务器上禁用tcp时间戳来消除连接超时。禁用窗口缩放对这个问题没有影响。追求禁用tcp时间戳的含义对于serverfault.com来说似乎是一个问题,因此我将看到有关在此迁移该问题的信息。 更新2 比较有效的连接(Win2003 / SQL2003)和不可用的连接(Win2008R2 / SQL2008R2)的数据包跟踪,我注意到Win2003连接的keepalive没有选项(即使它在较早的数据包中使用tcp时间戳记也是如此) ),并且断开的连接的keepalive(除非禁用了时间戳)在keepalive中确实具有tcp选项,即时间戳。因此,现在看来,Ubuntu机器对不带tcp选项的keepalive响应,而忽略了带tcp选项的keeplives。这实际上是有关两台主机上的tcp / ip问题的问题。 最终更新 我在Linux网络开发人员列表上提出了这个问题,现在我确信该问题是由于Windows错误导致具有tcp时间戳的tcp keepalive生成错误的校验和(但显然没有其他数据包) )。请参阅netdev列表上的线程。这个问题应该结束。     

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)