У нас есть приложение, которое делает много вызовов удаленному веб-серверу / службе. Клиентское приложение - это JBoss / Java в Linux (Red Hat 5), удаленный сервер - Windows 2008. На пути есть Cisco ACE, но NAT не работает.
Мы заметили, что когда Linux / JBoss повторно использует исходный порт для выполнения HTTP-вызова, мы можем получить «Соединение отклонено». Это когда клиент повторно использует указанный исходный порт в течение пары минут.
Когда я запускаю tcpdump / wirehark с обеих сторон, я вижу что-то вроде этого:
Запрос №1: порт источника 6666, порт назначения 80
Клиент -> Сервер Syn -> Клиент Syn ACK -> Клиент ACK -> GET / Сервер -> Клиент возврата данных -> Сервер ACK -> Клиент FIN ACK -> СЕРВЕР FIN ACK -> ACK
Запрос №2: Один и тот же порт источника и назначения - успех.
Запрос №3: Один и тот же порт источника и назначения - успех.
Запрос №4: Тот же порт источника и назначения, но на этот раз сбой («Соединение отклонено»), и это выглядит так:
Клиент -> Клиент SYN -> Клиент SYN (повторная передача) -> RST, ACK
Сервер видит оба SYN, но никогда не отправляет ACK или RST (он видит RST от клиента).
После некоторого поиска я обнаружил потенциальную проблему с отметками времени TCP. Мы убедились, что ACE пропустит их, и я могу убедиться, что Windows их видит. Я также вижу соединение в состоянии TIME_WAIT на стороне сервера / Windows (но я вижу это даже после 1-го успешного GET и № 2 и № 3, и все они были успешными). Порт не открыт или находится в состоянии TIME_WAIT на стороне клиента.
Одно место, на которое я смотрел, - это уменьшить запись реестра TcpTimedWaitDelay на стороне Windows до 30 секунд. Я еще не делал этого и не тестировал это, но думаю, что это должно сработать, если наша проблема существует.
Я увеличил количество портов на стороне клиента / Linux до 15000 - 60000 (со значения по умолчанию 30000 до 60000), но безрезультатно (просто надеясь, что увеличение числа доступных портов приведет к увеличению времени задержки из-за случайности использования исходный порт)
Мне кажется странным, что сторона сервера / Windows видит, что SYN проходит, но не отвечает, что заставляет меня думать, что он думает, что SYN от предыдущего сеанса или что-то в этом роде.
Я не уверен, что мне бы это понравилось, но мне было интересно, есть ли способ запретить Linux повторно использовать исходный порт, если он недавно использовался? Как какая-то задержка в этой логике (если она есть)?
Это не похоже на то, что у нас заканчиваются доступные порты или что-то еще, но иногда, поскольку это случайно, исходный порт действительно повторно используется в течение нескольких минут, и именно тогда мы видим проблемы.
У всех вас есть другие мысли по этому поводу?
Спасибо!
ОБНОВИТЬ
Я установил TcpTimedWaitDelay на 30 секунд на сервере Windows. Если вызов с повторно используемым портом-источником поступает через 30 секунд, проблем нет.
Я считаю, что ACE все еще виноват в некоторых отношениях, и это может быть своего рода защита от SYN-атак (ACE - это устройство безопасности), как будто я обхожу ACE, у меня нет проблем.
Но установка 2MSL на 30 секунд кажется на данный момент достаточно хорошим решением.
Я недостаточно знаю о циклическом переключении сокетов Windows, чтобы ответить на этот вопрос, но я предполагаю, что сервер закрывает соединения, и сокеты сидят в TIME_WAIT
состояние, в котором их нельзя использовать снова, пока не истечет срок их действия.
«Правильный» способ решить эту проблему - добавить больше кортежей - увеличить исходящие порты на клиенте (что вы и сделали), добавить порты прослушивания на сервере, добавить псевдонимы IP в свои интерфейсы и заставить приложения использовать эти дополнительные IP-адреса. / порты.
«Менее правильный» способ - уменьшить тайм-аут TW, который, я думаю, вы делаете с TcpTimedWaitDelay
.
«Совсем не самый правильный, но все же довольно популярный» способ - включить переработку сокетов, в Linux есть варианты tw_reuse
и tw_recycle
, может быть в Windows есть аналог.
Последние две опции нарушают TCP RFC. Может быть, у ACE проблемы с этим?