Соединения JDBC из Linux в MS SQL Server 2008 прерываются через 40 секунд

[ См. Обновления внизу ]

Я использую 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) и текущий драйвер JDBC 3.0 от MS (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), я заметил, что для поддержки активности для соединения Win2003 нет параметров (хотя он использует временные метки tcp в более ранних пакетах), а поддержка активности для разорванного соединения (если временные метки не отключены) имеет параметры tcp в keepalive, а именно временные метки. Итак, теперь похоже, что машина с Ubuntu отвечает на пакеты поддержки активности без параметров tcp, но игнорирует пакеты сообщений с параметрами tcp. Это действительно вопрос о проблемах TCP / IP на двух хостах.

Заключительное обновление Я преследовал этот вопрос в списке сетевых разработчиков Linux, и теперь я убежден, что проблема связана с ошибкой Windows, из-за которой генерируются неверные контрольные суммы для пакетов поддержки активности tcp с временными метками tcp (но, очевидно, для других пакетов) . См. Ветку в списке netdev . Этот вопрос следует закрыть.

5
задан ChuckB 13 June 2011 в 14:04
поделиться