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

从Linux到MS SQL Server 2008的JDBC连接在40秒后超时,linux,sql-server-2008,jdbc,Linux,Sql Server 2008,Jdbc,[请参见底部的更新 我使用JDBC在Windows2008R2机器上运行针对SQLServer2008R2的语句,该机器运行Ubuntu10.04LTS和2.6.32-32-Server内核。我正在使用当前的Sun Java 6 Ubuntu版本(Sun-java6-jdk 6.24-1build0.10.04.1)和MS当前的JDBC 3.0驱动程序(sqljdbc_3.0.1301.101_enu) 当语句完成所需时间超过40秒且未返回结果集(例如“stmt.executeUpdate(“S

[请参见底部的更新

我使用JDBC在Windows2008R2机器上运行针对SQLServer2008R2的语句,该机器运行Ubuntu10.04LTS和2.6.32-32-Server内核。我正在使用当前的Sun Java 6 Ubuntu版本(Sun-java6-jdk 6.24-1build0.10.04.1)和MS当前的JDBC 3.0驱动程序(sqljdbc_3.0.1301.101_enu)

当语句完成所需时间超过40秒且未返回结果集(例如“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 res=stmt.executeQuery(“SELECT*FROM FOO”)),则连接不会超时

当我在Win2003R2上对SQL2005中的数据库副本运行同一语句而不返回ResultSet时,该语句将在40秒时完成,而不会重置连接

我启用了日志记录,并将完成的SQL2005语句的日志与未完成的SQL2008R2语句的日志进行了比较,它们是与2008查询中的连接重置消息相当的逐行日志;见下午12:54:47的线路:

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通信量,我注意到2008和2005服务器都在语句开始执行30秒后向Linux发送TCP keep-alive数据包;Linux主机使用ACK从2005服务器确认keep alive,但在与2008服务器的连接中,Linux主机不发送ACK,2008服务器在重置连接之前重新传输keep alive 9次(每秒一次)(因此,直到超时的时间为40秒)。现在我注意到,Win2003/SQL2005和Win2008R2/SQL2008R2主机传输的保持活动数据包之间存在差异:较新的操作系统使用TCP窗口缩放,窗口大小为66560。所以现在我想知道TCP窗口大小>65535是否会导致iptables或Linux机器上的TCP/ip堆栈以静默方式忽略数据包。但是之前连接中的其他数据包也具有66560的缩放窗口大小,并且它们被Linux服务器确认。日志文件中没有任何内容表明这些数据包正在被丢弃或导致任何类型的问题

最后一点注意:在解决这个问题的过程中,由于更新的原因,我们不得不重新启动Linux服务器几次,两次连接都没有超时运行一两天

所以我很困惑,我希望你们中的一个能给我一个线索

更新

我发现可以通过在Linux服务器上禁用tcp时间戳来消除连接超时。禁用窗口缩放对问题没有影响。对于serverfault.com来说,研究禁用tcp时间戳的含义似乎更像是一个问题,因此我将在那里了解如何迁移这个问题

更新2

比较有效连接(Win2003/SQL2003)和无效连接(Win2008R2/SQL2008R2)的数据包跟踪,我注意到Win2003连接的keepalive没有选项(即使它在早期数据包中使用tcp时间戳),而断开连接的keepalive(除非时间戳被禁用)keepalive中没有tcp选项,即时间戳。因此,现在看起来Ubuntu机器在不使用tcp选项的情况下响应keeplives,但在使用tcp选项的情况下忽略keeplives。这实际上是关于两台主机上的tcp/ip问题

最终更新
我在Linux networking dev列表中提出了这个问题,现在我确信这个问题是由Windows错误造成的,该错误导致为具有tcp时间戳的tcp keepalives生成错误的校验和(但显然,没有其他数据包)。这个问题应该结束。

事实证明,Win2008发送的带有tcp时间戳的tcp keepalives具有不正确的tcp校验和,这导致Linux主机正确地忽略了它们。这个问题几乎肯定是一个Windows bug,而不是编程或Linux内核问题。请参阅。

我发现Windows Server 2003和SQL Server在具有启用TCP/IP卸载的网络适配器的计算机上与可扩展网络包(SNP)存在类似的问题

此处的信息和解决方案:


我现在的雇主也遇到了同样的问题。我们偶然发现,如果Windows2008R2服务器的“烟囱卸载状态”设置为Enabled,那么同样的断开会在40秒后发生。如果将该设置设置为自动,则工作正常。

我们确实看到了相同的问题,当问题发生时,“烟囱卸载状态”设置为启用,但应禁用。


我们发现的根本原因是,服务器上应用的一个语义修补程序将此标志重置为Enabled

我开始认为这个问题应该出现在serverfault.com上,而不是stackoverflow.com上。我正在考虑迁移它。进一步的调查使我确信问题在tcp/ip协议栈的层次上,如果问题被迁移,上述问题的措辞只会转移到真正的问题上。所以我现在的愿望是这个问题简单地结束,我可以在serverfault.com上问一个更直接、更相关的问题。