Chu*_*ckB 5 linux jdbc sql-server-2008
[ 见底部更新 ]
我正在使用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)
Run Code Online (Sandbox Code Playgroud)
如果我的语句确实返回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)
[...]
Run Code Online (Sandbox Code Playgroud)
以下是针对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)
[...]
Run Code Online (Sandbox Code Playgroud)
我使用tcpdump捕获SQL Server主机和Linux主机之间的所有流量以及所有ICMP流量,我注意到2008和2005服务器都在语句开始执行后30秒向Linux发送TCP保持活动数据包; Linux主机确认保持活动从用一个ACK 2005服务器,但在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的连接的存活时间没有选择(尽管它使用TCP时间戳前面包) ,以及断开连接的keepalive(除非禁用时间戳)确实在keepalive中有tcp选项,即时间戳.所以现在看起来Ubuntu机器在没有tcp选项的情况下响应keepalive但忽略了使用tcp选项的keeplive.这实际上是关于两台主机上的tcp/ip问题的问题.
最后更新 我追求的Linux网络开发列表关于这个问题,现在我相信,这个问题是由于Windows错误会导致错误校验对于具有TCP时间戳(但是,显然TCP持久连接中产生,不为别的包).请参阅netdev列表中的主题.这个问题应该结束.
事实证明,Win2008发送的带有tcp时间戳的tcp keepalive具有不正确的tcp校验和,这导致Linux主机正确地忽略它们.这个问题几乎肯定是Windows错误,而不是编程或Linux内核问题.请参阅Linux网络开发列表中的此主题.