Что может привести к тому, что TCP/IP будет отбрасывать пакеты без разрыва соединения?

У меня есть веб-приложение и клиент, написанные на Java. Что бы это ни стоило, клиент и сервер находятся в Windows. Клиент отправляет запросы HTTP GET через Apache HttpClient. Сервер блокируется на срок до минуты, и если в течение этой минуты клиенту не поступило никаких сообщений, сервер возвращает HTTP 204 No Content. В противном случае, как только сообщение готово для клиента, оно возвращается с телом HTTP 200 OK.

Вот что меня озадачило: время от времени для определенного подмножества клиентов (всегда клиентов с заведомо ненадежным сетевым подключением) клиент выдает GET, сервер получает и обрабатывает GET, но клиент сидит навсегда. Включив логи отладки для клиента, я вижу, что HttpClient все еще ждет самую первую строчку ответа.

На сервере нет исключений, по крайней мере, нигде ничего не зарегистрировано, ни Tomcat, ни мое веб-приложение. Судя по журналам отладки, есть все признаки того, что сервер успешно ответил клиенту. Однако клиент не показывает никаких признаков получения чего-либо. Клиент зависает на неопределенное время в HttpClient.executeMethod. Это становится очевидным после того, как время сеанса истекает, и клиент предпринимает действия, которые заставляют другой поток выдавать HTTP POST. Конечно, POST завершается ошибкой, потому что срок действия сеанса истек. В некоторых случаях между истечением срока действия сеанса и отправкой клиентом POST и обнаружением этого факта прошло часы. Все это время executeMethod все еще ждет строку ответа HTTP.

Когда я использую WireShark, чтобы увидеть, что на самом деле происходит на уровне проводов, этого сбоя не происходит. То есть этот сбой произойдет в течение нескольких часов для конкретных клиентов, но когда WireShark запущен на обоих концах, эти же клиенты будут работать всю ночь, 14 часов, без сбоя.

Кто-нибудь еще сталкивался с чем-то подобным? Что в мире может вызвать это? Я думал, что TCP/IP гарантирует доставку пакетов даже при кратковременных сетевых сбоях. Если я устанавливаю SO_TIMEOUT и немедленно повторяю запрос по тайм-ауту, повторная попытка всегда завершается успешно. (Конечно, я сначала отменить запрос с истекшим временем ожидания и разорвать соединение, чтобы гарантировать использование нового сокета.)

Мысли? Идеи? Есть ли какой-либо параметр TCP/IP, доступный для Java, или параметр реестра в Windows, который активирует более агрессивные повторные попытки TCP/IP для потерянных пакетов?


person Eddie    schedule 24.04.2009    source источник
comment
Похоже, наблюдение меняет результат — › Heisenbug — › что-то не так с многопоточностью. В этом случае похоже, что кто-то работает слишком быстро (я бы поставил свои деньги на HttpClient) и из-за этого просто зависает. Возможно, вы столкнулись с ошибкой в ​​самом HttpClient, надеюсь, другие могут быть более полезными и помочь вам с этой проблемой.   -  person Esko    schedule 25.04.2009


Ответы (6)


Вы абсолютно уверены, что сервер успешно отправил ответ клиентам, которые, похоже, отказали? Под этим я подразумеваю, что сервер отправил ответ, и клиент подтвердил этот ответ обратно на сервер. Вы должны увидеть это, используя wireshark на стороне сервера. Если вы уверены, что это произошло на стороне сервера, а клиент по-прежнему ничего не видит, вам нужно смотреть дальше по цепочке от сервера. Используются ли какие-либо прокси/обратные прокси-серверы или NAT?

Транспорт TCP считается надежным протоколом, но он не гарантирует доставку. Стек TCP/IP вашей ОС будет очень стараться передать пакеты на другой конец, используя повторную передачу TCP. Вы должны увидеть это в wirehark на стороне сервера, если это происходит. Если вы видите чрезмерные повторные передачи TCP, обычно это проблема сетевой инфраструктуры, то есть плохое или неправильно настроенное оборудование/интерфейсы. Повторные передачи TCP отлично работают при коротких прерываниях сети, но плохо работают в сети с более длительными прерываниями. Это связано с тем, что стек TCP/IP будет отправлять повторные передачи только после истечения таймера. Этот таймер обычно удваивается после каждой неудачной повторной передачи. Это сделано для того, чтобы избежать переполнения и без того проблемной сети повторными передачами. Как вы можете себе представить, это обычно вызывает у приложений всевозможные проблемы с тайм-аутом.

В зависимости от топологии вашей сети вам также может понадобиться разместить probes/wireshark/tcpdump в других промежуточных местах в сети. Вероятно, потребуется некоторое время, чтобы выяснить, куда ушли пакеты.

На вашем месте я бы продолжал отслеживать с помощью wireshark на всех концах, пока проблема не возникнет снова. Скорее всего будет. Но, похоже, вы в конечном итоге обнаружите то, о чем уже упоминали, — ненадежное оборудование. Если об исправлении ненадежного оборудования не может быть и речи, вам может потребоваться просто создать дополнительные тайм-ауты на уровне приложения и повторные попытки, чтобы попытаться решить проблему в программном обеспечении. Похоже, вы начали идти по этому пути.

person Gary    schedule 25.04.2009
comment
Все, что я могу сказать из отладки на месте, когда это произошло, это то, что мое веб-приложение считает, что оно ответило. Я не включал отладку в самом Tomcat (6.x), чтобы проверить, считает ли он, что ответ завершен. Ни в журнале Tomcat, ни в журнале Apache HTTPD, ни в журнале mod_jk жалоб не было. Ненадежное оборудование полностью не в моих руках ... в некоторых случаях люди выходят в общедоступный Интернет. - person Eddie; 25.04.2009
comment
Нет никакой замены достоверной информации. Wireshark скажет вам, кто говорит, а кто нет. - person Hans Malherbe; 23.06.2009

Я не видел этого как такового, но я видел аналогичные проблемы с большими дейтаграммами UDP, вызывающими фрагментацию IP, что приводит к перегрузке и, в конечном итоге, к потере кадров Ethernet. Поскольку это TCP/IP, я не ожидаю, что фрагментация IP будет большой проблемой, поскольку это протокол на основе потоков.

Я замечу одну вещь: TCP не гарантирует доставку! Не может. Это гарантирует, что если вы отправите байт A, за которым следует байт B, то вы никогда не получите байт B до тех пор, пока не получите байт А.

С учетом сказанного я бы подключил клиентскую машину и машину мониторинга к концентратору. Запустите Wireshark на машине мониторинга, и вы сможете увидеть, что происходит. Я столкнулся с проблемами, связанными как с обработкой пробелов между HTTP-запросами, так и с неправильными размерами блоков HTTP. Обе проблемы были связаны с написанным вручную стеком HTTP, поэтому это проблема только в том случае, если вы используете ненадежный стек.

person D.Shawley    schedule 24.04.2009

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

В частности, если забыть закрыть, сокет останется висящим до тех пор, пока сборщик мусора не восстановит его и не вызовет finalize().

person Lawrence Dol    schedule 25.04.2009

Если вы используете длительно работающие GET, вы должны установить тайм-аут на стороне клиента в два раза больше, чем тайм-аут сервера, как вы обнаружили.

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

Клиент обнаружит, что сокет закрыт на стороне сервера, только когда он отправит больше данных в этот сокет, а сервер отклонит эти новые данные и закроет сокет.

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

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

person Simeon Pilgrim    schedule 23.06.2009

Могут ли на этих компьютерах быть установлены вирусы/вредоносные программы? При использовании wireshark устанавливается winpcap (http://www.winpcap.org/), который может переопределять изменения, внесенные созданное вредоносное ПО (или вредоносное ПО может просто обнаружить, что за ним наблюдают, и не предпринимать никаких подозрительных действий).

person BarrettJ    schedule 24.04.2009
comment
Я не рассматривал это, но это, конечно, отдаленно возможно. Поскольку я вижу это только на клиентах с ненадежным сетевым подключением, я до сих пор предполагал, что сама нестабильность является какой-то причиной. - person Eddie; 25.04.2009
comment
Вредоносное ПО удаленно возможно, но очень маловероятно. Идите с тем, что вы уже знаете, — с ненадежностью. - person Gary; 25.04.2009

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

person Peter Lawrey    schedule 25.04.2009