Что может вызвать сокет ConnectException: истекло время ожидания соединения? - PullRequest
10 голосов
/ 07 октября 2010

У нас есть клиент Webstart, который связывается с сервером путем отправки сериализованных объектов по HTTPS с использованием java.net.HttpsURLConnection.

Все отлично работает на моей локальной машине и на тестовых серверах, расположенных в нашем офисе, но я 'Я испытываю очень, очень странную проблему, которая возникает только на наших производственных и промежуточных серверах (причем время от времени).Основное различие, которое я знаю между этими серверами и теми, которые находятся в нашем офисе, состоит в том, что они расположены в другом месте, и связь клиент-сервер с ними значительно медленнее, но до этого она работала в течение долгого времени.

В любом случае, вот что происходит:

  • Клиент, после установки таких параметров, как время ожидания чтения и свойства, такие как Content-Type на HttpURLConnection, вызывает getOutputStream() для него, чтобы получитьпоток для записи.
  • На этом этапе, насколько я могу судить, клиент зависает на некоторое время.
  • Затем клиент выдает следующее исключение:
java.net.ConnectException: Connection timed out: connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(Unknown Source)
    at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.SocksSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.connect(Unknown Source)
    at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.connect(Unknown Source)
    at sun.net.NetworkClient.doConnect(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.http.HttpClient.openServer(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.(Unknown Source)
    at sun.net.www.protocol.https.HttpsClient.New(Unknown Source)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source)

Обратите внимание, что это не SocketTimeoutException, который метод connect() в HttpURLConnection говорит, что он выбрасывает, если время ожидания истекает до установления соединения.Кроме того, когда это происходит, я могу позвонить conn.getResponseCode() и получить код ответа 200.

  • На стороне сервера в конструктор ObjectInputStream добавляется EOFException,который пытается прочитать заголовок сериализации, но терпит неудачу, потому что клиент никогда не получает OutputStream для записи.

В случае, если это помогает, вот вызовы, сделанные на HttpsURLConnection довызов getOutputStream() (отредактирован, чтобы показывать только выполняемые вызовы, а не всю структуру кода, делающего это):

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setReadTimeout(30000);
conn.setRequestProperty("Cookie", cookie);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-java-serialized-object");
conn.getOutputStream();

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

Учитываячто я смог найти до сих пор о java.net.ConnectException: Connect timed out, я подумал, не было ли это какой-то проблемы с сетью или брандмауэром в сети, на которой работают наши серверы ... но это не имеет большого смысла для меня, учитывая, чтозапросявно доходит до сервлета.Кроме того, другие приложения, работающие в той же сети, не сообщали о похожих проблемах.

Кто-нибудь имеет какое-либо представление о причинах этого или даже о том, что мне следует выяснить?

1 Ответ

9 голосов
/ 07 октября 2010

Мы сталкивались с этим в подобном случае с вашим.Обычно при высокой нагрузке и непросто воспроизвести на тесте.Пока не исправили, но это шаги, которые мы прошли.

Если это проблема с брандмауэром, мы получим отказ в подключении или исключение SocketTimeout.

1) Вы можете отслеживатьэти запросы в журнале доступа на сервере - показывают ли они статус HTTP 200 или 404 или что-то еще?В нашем случае журналы сервера (в данном случае IIS) показали, что клиент закрыл соединение, а не сервер.Так что это было загадкой.

Обновление: Если клиент всегда получает 200, то сервер фактически отправил обратно некоторый ответ, но я подозреваю, что размер байта ответа (если это записанов журналах доступа) покажет значение, отличное от значения обычного размера ответа для этого запроса.

Если он показывает тот же размер ответа, то у вас есть (может быть невероятное) условие, что сервер действительно ответил правильно , но клиент не получил ответ обратно, потому что соединение разорвано где-то посередине.

2) Группы сетевых администраторов посмотрели на TCP / IPтрафик, чтобы определить, какой конец (или промежуточный маршрутизатор) завершает диалог HTTP / TCP-IP.И как только мы понимаем, с какой целью заканчивается соединение, стоит посмотреть, почему.Кто-то, обладающий достаточными знаниями, может выполнить snoop

3) На сервере настроено / ограничено максимальное количество запросов - и это ограничивает ваши соединения?

4)Есть ли промежуточные балансировщики нагрузки, при которых запросы могут быть отброшены?

Обновление: Еще одна вещь, которую мы хотели, но не выполнили, - это создать статический маршрут между клиентом и сервером, чтобы уменьшитьколичество переходов между ними и убедитесь, что сетевое соединение не прерывается.См. http://en.wikipedia.org/wiki/Static_routing

5) Другим предложением является настройка ConnectTimeout , чтобы увидеть, работают ли они с более высоким значением. Обновление: Возможно, вы захотите попробовать conn.getErrorStream ()

Возвращает поток ошибок, если соединение не удалось, но сервер тем не менее отправил полезные данные.Если соединение не было подключено, или если у сервера не было ошибки при подключении, или если сервер имел ошибку, но данные об ошибках не были отправлены, этот метод возвратит нуль.

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

Обновление: На сегодняшний день мы научились жить сэта проблема, потому что мы насчитали 200-300 из 400 000 запросов в день, что составляет 0,00075%

...