[见底部更新]
我正在使用JDBC从运行带有2.6.32-32服务器内核的Ubuntu 10.04 LTS的计算机上运行Windows 2008 R2计算机上的sql Server 2008 R2语句.我正在使用当前的Sun Java 6版本用于Ubuntu(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秒内没有重置连接.
我启用了日志记录,并将完成的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保持活动数据包; Linux主机通过ACK确认来自2005服务器的keep-alive,但是在连接到2008服务器时,Linux主机不发送ACK,2008服务器重新发送保持活动9次(每秒一次),然后重置连接(因此直到超时的40秒时间).现在我注意到Win2003 / sql2005和Win2008R2 / sql2008R2主机传输的保持活动包之间存在差异:较新的操作系统使用TCP窗口缩放,窗口大小为66560.所以现在我想知道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选项的keeplive.这实际上是关于两台主机上的tcp / ip问题的问题.
最后更新
我在Linux网络开发列表中追问这个问题,我现在说服问题是由于Windows错误导致为具有tcp时间戳的tcp keepalive生成错误的校验和(但显然,没有其他数据包) . See the thread on the netdev list.这个问题应该结束.
最佳答案:
事实证明,Win2008发送的带有tcp时间戳的tcp keepalive具有不正确的tcp校验和,这导致Linux主机正确地忽略它们.这个问题几乎肯定是Windows错误,而不是编程或Linux内核问题.见this thread on the Linux networking dev list.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。