[ См. Обновления внизу ]
Я использую JDBC для запуска операторов против SQL Server 2008 R2 на компьютере под управлением Windows 2008 R2 с компьютера под управлением Ubuntu 10.04 LTS с 2.6.32-32-серверное ядро.Я использую текущую сборку 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 »)»), время соединения не истекает.
Когда я выполняю тот же оператор, не возвращаяResultSet для копии базы данных в SQL2005 на Win2003R2, оператор завершается без сброса соединения за 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 гг. отправляют Linux пакет поддержки TCP через 30 секунд после начала выполнения оператора;узел Linux подтверждает подтверждение активности с сервера 2005 года с помощью ACK, но при подключении к серверу 2008 года узел Linux не отправляет подтверждение ACK, а сервер 2008 повторно передает подтверждение активности 9 раз (один раз в секунду) перед сбросомсоединение (отсюда 40-секундный период до истечения времени ожидания).Теперь я заметил, что существует разница между пакетами поддержки активности, передаваемыми хостами Win2003 / SQL2005 и Win2008R2 / SQL2008R2: более новая ОС использует масштабирование окна TCP с размером окна 66560. Так что теперь мне интересно, если размер окна TCP> 65535вызывает iptables или стек tcp / ip на машине Linux, чтобы игнорировать пакет в молчании.Но тогда другие пакеты ранее в соединении также имеют масштабированный размер окна 66560, и они подтверждаются сервером Linux.В файлах журналов нет ничего, что указывало бы на то, что эти пакеты отбрасываются или вызывают какие-либо проблемы.
И последнее замечание: в ходе устранения этой проблемы нам пришлось перезагрузить сервер Linux.пару раз из-за обновлений, и оба раза соединения работали без перерыва в течение одного или двух дней.
Так что я озадачен, и я надеюсь, что один из вас может иметь подсказку для меня.
Обновление
Я обнаружил, что могу устранить время ожидания подключения, отключив временные метки tcp на сервере Linux.Отключение масштабирования окна не влияет на проблему.Преследование последствий отключения временных меток tcp кажется больше вопросом для serverfault.com, поэтому я посмотрю о переносе этого вопроса туда.
Обновление 2
Сравнение трассировок пакетов для работающего соединения (Win2003 / SQL2003) с тем, которое не работает (Win2008R2 / SQL2008R2), я заметил, чтоу keepalive для соединения Win2003 нет опций (даже если он использует временные метки tcp в более ранних пакетах), а для keepalive для разорванного соединения (если не отключены временные метки) в keepalive есть опции tcp, а именно временные метки.Так что теперь похоже, что машина Ubuntu отвечает на keepalive без параметров tcp, но игнорирует keeplives с параметрами tcp.Это действительно вопрос о проблемах tcp / ip на двух хостах.
Окончательное обновление Я занимался этим вопросом в списке сетевых разработчиков Linux, и теперь я убежден, что проблема связана с ошибкой Windows, которая приводит к созданию неверных контрольных сумм для пакетов поддержки активности tcp, имеющих временные метки tcp (но, очевидно, для других пакетов), См. Тему в списке сетевых устройств .Этот вопрос должен быть закрыт.