2014-01-22 5 views
2

Я немного смущен следующим случаем.Интерфейс PostgresSQL неожиданно закрывает соединение

У меня есть сервер Postgres, работающий на хосте A, и клиент на основе java, работающий на хосте B. Клиент использует драйвер JDBC org.postgresql.Driver (версия 9.1-901.jdbc3).

Иногда при выполнении длительной хранимой процедуры я получаю исключение «java.net.SocketException: Socket closed». Я использую org.apache.commons.dbcp.BasicDataSource для получения соединений .

Пул DBCP настроен по умолчанию.

У меня есть дамп tcp, чтобы выяснить, на какой стороне (клиент или сервер) закрывается сокет;

Вот что я получил:

1. Client B sends a test query message when tries to borrow connection from dbcp pool ("Select 1") 
2. Server A sends successful response back (Type: Command completion, Ready for query) 
3. Client B sends ACK message in response on server A response (see the item 2). 
4. Client B sends query message to the server A. 
5. Server A sends ACK message in response on client Query message (see the item 4). 
6. Client B sends terminating message (Type : Termination) after some time passed (from 3 to 10 or sometimes even more minutes). 
7 Client B sends FIN ACK message to the server. 
8. Server A sends back ACK on termination message. 
9. Server A sends ACK on (FIN, ACK) message (item 7). 
10. Server A sends back a response on the client query (from item 4) Type: Row description Columns: 40. 
11. Client B sends RST message (reset). 
12. Server A continues sending response on the query Type: Data row Length: 438 Columns 40 and so on. 
13 Client B sends RST message (reset) again. 
14. Server A continues sending response on the query Type: Data row Length: 438 Columns 40 and so on. 
15. Client B sends RST message (reset). 

После кажется, закончена, что связь.

После пункта 6, в моих клиентских журналах я получил исключение вроде следующего:

Caused by: java.net.SocketException: Socket closed 
     at java.net.SocketInputStream.socketRead0(Native Method) 
     at java.net.SocketInputStream.read(SocketInputStream.java:152) 
     at java.net.SocketInputStream.read(SocketInputStream.java:122) 
     at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:145) 
     at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:114) 
     at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:73) 
     at org.postgresql.core.PGStream.ReceiveChar(PGStream.java:274) 
     at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1661) 
     at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257) 

Не могли бы вы мне помочь, чтобы выяснить причину такого отказа. (Эта ошибка происходит один раз за 10 успешных случаев.)

Заранее благодарен!

+1

Что, если угодно, появляется в журналах ошибок PostgreSQL? Рассмотрите возможность перезапуска PostgreSQL с помощью 'log_min_messages = debug3' для подробных подробных (и больших) журналов. Вам понадобится соответствующее 'log_line_prefix', чтобы вы могли определить, какой из них является сеансом. Также, версия PostgreSQL? ('SELECT version()'). Наконец, что такое сеть, как между клиентом и сервером? Сколько хмелей? Интернет или только LAN? Wi-Fi включен? любые NAT, брандмауэры, прокси, маршрутизаторы отслеживания соединений? –

ответ

0

У нас была аналогичная проблема, и это было вызвано межсетевым экраном или маршрутизатором отслеживания соединений между сервером и клиентом.

Я предполагаю, что вы взяли tcpdump на стороне сервера. Запрос выполняется в течение значительного времени без трафика в соединении. Брандмауэр имеет таймер в открытом соединении; он истекает, и брандмауэр закрывает соединение к серверу, а также обратно к клиенту. При захвате на стороне сервера, похоже, клиент закрывает соединение.

Вы можете проверить это, выполнив захват на стороне клиента одновременно с захватом на стороне сервера - на стороне клиента это будет выглядеть так, как сервер закрыл соединение, тогда как на стороне сервера он выглядит так, как будто сервер закрывается связь. В действительности брандмауэр закрывает его в обоих направлениях.

Для предотвращения этого вы можете установить tcp_keepalives_idle, tcp_keepalives_interval и/или tcp_keepalives_count (если ваша ОС поддерживает TCP Keepalives). Кроме того, вам придется изменить настройки на брандмауэре.