Linux уменьшить time wait

Обновлено: 04.07.2024

Без сомнений, самым сложным для понимания аспектом TCP в отношении сетевого программирования является состояние TIME_WAIT (время ожидания). На рис. 2.4 мы видим, что узел, выполняющий активное закрытие, проходит это состояние. Продолжительность этого состояния равна двум MSL (maximum segment lifetime — максимальное время жизни сегмента), иногда этот период называется 2MSL.

Пакеты в объединенных сетях обычно теряются в результате различных аномалий. Маршрутизатор отключается, или нарушается связь между двумя маршрутизаторами, и им требуются секунды или минуты для стабилизации и нахождения альтернативного пути. В течение этого периода времени могут возникать петли маршрутизации (маршрутизатор А отправляет пакеты маршрутизатору В, а маршрутизатор В отправляет их обратно маршрутизатору А), и пакеты теряются в этих петлях. В этот момент, если потерянный пакет — это сегмент TCP, истекает установленное время ожидания отправляющего узла, и он снова передает пакет, и этот заново переданный пакет доходит до конечного места назначения по некоему альтернативному пути. Но если спустя некоторое время (не превосходящее количества секунд MSL после начала передачи потерянного пакета) петля маршрутизации исправляется, пакет, потерянный в петле, отправляется к конечному месту назначения. Начальный пакет называется потерянной копией или дубликатом (lost duplicate), а также блуждающей копией или дубликатом (wandering duplicate). TCP должен обрабатывать эти дублированные пакеты.

Есть две причины существования состояния TIME_WAIT:

? необходимо обеспечить надежность разрыва двустороннего соединения TCP;

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

Чтобы понять вторую причину, по которой необходимо состояние TIME_WAIT, давайте считать, что у нас имеется соединение между IP-адресом 12.106.32.254, порт 1500 и IP-адресом 206.168.112.219, порт 21. Это соединение закрывается, и спустя некоторое время мы устанавливаем другое соединение между теми же IP-адресами и портами: 12.106.32.254, порт 1500 и 206.168.112.219, порт 21. Последнее соединение называется новым воплощением (incarnation) предыдущего соединения, поскольку IP-адреса и порты те же. TCP должен предотвратить появление старых дубликатов, относящихся к данному соединению, в новом воплощении этого соединения. Чтобы гарантировать это, TCP запрещает установление нового воплощения соединения, которое в данный момент находится в состоянии TIME_WAIT. Поскольку продолжительность состояния TIME_WAIT равна двум MSL, это позволяет удостовериться, что истечет и время жизни пакетов, посланных в одном направлении, и время жизни пакетов, посланных в ответ. Используя это правило, мы гарантируем, что в момент успешного установления соединения TCP время жизни в сети всех старых дубликатов от предыдущих воплощений этого соединения уже истекло.

Данный текст является ознакомительным фрагментом.

Продолжение на ЛитРес

Состояние процесса

Состояние процесса Поле state дескриптора процесса описывает текущее состояние процесса (рис. 3.3). Каждый процесс в системе гарантированно находится в одном из пяти различных состояний. Рис. 3.3. Диаграмма состояний процессаЭти состояния представляются значением одного из

6.2. Состояние

6.2. Состояние Понятие состояния (state) является фундаментальным не только в метамоде-ли языка UML, но и в прикладном системном анализе. Ранее в главе 1 кратко были рассмотрены особенности представления динамических характеристик сложных систем, традиционно используемых для

Начальное состояние

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

Конечное состояние

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

6.5. Историческое состояние

6.5. Историческое состояние Как было отмечено выше, формализм обычного автомата не позволяет учитывать предысторию в процессе моделирования поведения объектов. Однако функционирование целого ряда систем основано на возможности выхода из отдельных состояний с

7.1. Состояние действия

7.1. Состояние действия Состояние действия (action state) является специальным случаем состояния с некоторым входным действием и по крайней мере одним выходящим из состояния переходом. Этот переход неявно предполагает, что входное действие уже завершилось. Состояние действия

Физическое и эмоциональное состояние

Физическое и эмоциональное состояние Казалось бы, очевидная вещь, хорошее физическое и эмоциональное состояние позволяет работать на порядок лучше, меньше уставать, быть более сконцентрированным. Это вроде бы все понимают, и, в то же время, только единицы уделяют этим

Состояние и версия записи

Состояние и версия записи Каждый объект DataRow имеет свойство RowState, которое обозначает текущее состояние или статус записи. Кроме того, каждая запись хранит информацию о четырех разных версиях своего значения. По мере редактирования записи изменяется ее состояние и версия

Статическое состояние

Статическое состояние Ключевое слово Static в объявлении переменной следует использовать тогда, когда вы хотите, чтобы переменная оставалась в памяти, - для того чтобы использовать ее значение - даже когда процедура завершила свою работу. В следующем примере переменная

Предыдущее состояние дел

Состояние готовности

8.4. Состояние планировщика событий

8.4. Состояние планировщика событий Информация относительно состояния планировщика события для отладки и целей поиска неисправностей может быть получена следующим образом:В MySQL 5.1.11 версиях -debug Вы можете использовать инструкцию SHOW SCHEDULER STATUS.Важно: эта инструкция была

4.4.1. Состояние гонки

4.4.1. Состояние гонки Предположим, что в программу поступает группа запросов, которые обрабатываются несколькими одновременными потоками. Очередь запросов представлена связанным списком объектов типа struct job.Когда каждый поток завершает свою операцию, он обращается к

Состояние

Состояние Триггер может быть активным (active) или неактивным (inactive). Запускаются только активные триггеры. См. замечания к ALTER TRIGGER по поводу подробностей деактивации

В результате у меня есть много сокетов, висящих в TIME_WAIT (график захвачен с настройками TCP ниже):

ВРЕМЯ ЖДЕТ

Я хотел бы уменьшить количество розеток.

Что я могу сделать кроме этого?

Обновление: некоторые подробности о фактической схеме обслуживания на машине:

Я, вероятно, должен также переключить балансировщик нагрузки -> подключение к рабочему сокету на доменные сокеты, но проблема с сокетами TIME_WAIT останется - я планирую добавить второго рабочего на отдельной машине в ближайшее время. Не сможет использовать доменные сокеты в этом случае.

Кажется, что Мунин бессовестно лжет. Смотрите комментарии к ответу Кайла. Глядя на это сейчас. Теперь похоже, что Мунин не лжет, а скорее смотрит на неправильный сюжет .

Так как это позади nginx. Означает ли это, что nginx действует как обратный прокси-сервер? Если это так, то ваши подключения в два раза (один к клиенту, один к вашим веб-серверам). Вы знаете, к какому концу эти гнезда принадлежат?

Обновление:
fin_timeout - это то, как долго они остаются в FIN-WAIT-2 (из networking/ip-sysctl.txt документации ядра):

Я думаю, что вы, возможно, просто должны позволить Linux сохранить номер сокета TIME_WAIT по сравнению с тем, что на них похоже, возможно, с ограничением 32 КБ, и именно здесь Linux перерабатывает их. Это 32k упоминается в этой ссылке :

Кроме того, я нахожу путаницу / proc / sys / net / ipv4 / tcp_max_tw_buckets. Хотя по умолчанию установлено значение 180000, я вижу сбой TCP, когда в моей системе установлены 32K сокеты TIME_WAIT, независимо от макс. Двух сегментов.

Эта ссылка также предполагает, что состояние TIME_WAIT составляет 60 секунд и не может быть настроено через proc.

Случайный интересный факт:
вы можете увидеть таймеры на тайм-ауте с netstat для каждого сокета с netstat -on | grep TIME_WAIT | less

Повторное использование против повторного использования:
это довольно интересно, оно выглядит как повторное использование, позволяет повторно использовать сокеты time_Wait, а повторное использование переводит его в режим TURBO:

Я бы не рекомендовал использовать net.ipv4.tcp_tw_recycle, так как это вызывает проблемы с клиентами NAT .

Может быть, вы могли бы попробовать не включать оба из них и посмотреть, какой эффект это имеет (попробуйте по одному и посмотрите, как они работают самостоятельно)? Я бы использовал netstat -n | grep TIME_WAIT | wc -l для более быстрой обратной связи, чем Munin.

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


Поскольку TCP-соединение является двунаправленным, при закрытии соединения необходимо закрыть оба направления. Сторона, отправляющая пакет FIN, сначала выполняет активное завершение работы, а сторона, отправляющая пакет FIN, позже выполняет пассивное завершение работы. Сторона, которая активно закрывается, перейдет в состояние TIME_WAIT и останется в этом состоянии в течение 2MSL.

Для состояния TIME_WAIT есть следующая картина:


Мы ориентируемся на несколько концепций:

Условия генерации TIME_WAIT: Активная закрывающая сторона перейдет в состояние TIME_WAIT после четырехкратной отправки последнего ACK с продолжительностью 2MSL (MSL в Linux составляет 30 секунд и не настраивается).

TIME_WAIT продолжает роль двух MSL: Во-первых, надежно и безопасно закройте TCP-соединение. Например, если сеть перегружена, если последний ACK активной закрывающей стороны не получен пассивной закрывающей стороной, то пассивная закрывающая сторона будет повторно передавать FIN с течением времени. В это время незакрытый TIME_WAIT будет иметь дело с этими хвостовыми проблемами. Влияние на новые подключения и другие услуги. Во-вторых, для предотвращения установления нового TCP-соединения из-за отсутствия непрерывного времени TIME_WAIT задержанный пакет повторной передачи FIN будет мешать новому соединению.

Ресурсы, занятые TIME_WAIT: Небольшой объем памяти (около 4К) и файловый дескриптор fd.

Вред от закрытия TIME_WAIT: Во-первых, когда состояние сети плохое, если у активной стороны нет ожидания TIME_WAIT, после закрытия предыдущего соединения активная сторона и пассивная сторона устанавливают новое TCP-соединение, а затем пассивная сторона повторно передает или прибывает задержанный пакет FIN Затем это напрямую повлияет на новое TCP-соединение; во-вторых, когда состояние сети плохое и в то же время нет ожидающего TIME_WAIT, нового соединения после закрытия соединения нет, тогда, когда пассивная сторона повторно передает или получен задержанный пакет FIN, он будет отправлен пассивной стороне. Отправка пакета RST может повлиять на другие сервисные соединения на пассивной стороне.

1. tcp_tw_recycle

Как следует из названияВосстановить соединение TIME_WAIT, Можно сказать, что этот параметр ядра стал панацеей для обработки TIME_WAIT. Если вы ищете решение TIME_WAIT в Интернете, вы порекомендуете установить его во всех случаях, но есть ловушка, которую нелегко обнаружить: когда несколько клиентов проходят Когда режим NAT подключен к сети и взаимодействует с сервером, сервер видит тот же IP-адрес, что означает, что эти клиенты фактически эквивалентны одному для сервера. Поскольку временные метки этих клиентов могут быть разными, сервер С конечной точки зрения, отметка времени может быть неупорядоченной, что напрямую приводит к тому, что пакет с маленькой отметкой времени отбрасывается. Ссылка: tcp_tw_recycle и tcp_timestamps вызывают сбой подключения.

Примечания:Рекомендуется не включать эту опцию. В настоящее время часто используется Internet NAT, что может привести к невозможности проведения трехстороннего рукопожатия.。

После открытия TIME_WAIT восстанавливается в пределах 3,5 * RTO (время RTO рассчитывается на основе времени RTT), а временная метка в запросе подключения к сокету того же исходного IP-хоста в течение 60 секунд должна быть увеличена. Для сервера тот же исходный IP-адрес может быть За NAT находится много машин. Приращение отметки времени на этих машинах не может быть гарантировано. Сервер отклоняет неинкрементные запросы на соединение, что напрямую приводит к сбою трехстороннего рукопожатия.

2. tcp_tw_reuse

Как следует из названияПовторно использовать соединение TIME_WAIT, При создании нового соединения, если возможно, рассмотрите возможность повторного использования соответствующего соединения TIME_WAIT. обычно думаю tcp_tw_reuse соотношение tcp_tw_recycle Это безопаснее, потому что, во-первых, время создания TIME_WAIT должно превышать одну секунду, прежде чем его можно будет повторно использовать; во-вторых, оно будет повторно использоваться только при увеличении метки времени соединения. В официальном документе сказано: если это безопасно с точки зрения протокола, его можно использовать. Это просто дипломатическая риторика! На мой взгляд, если сеть относительно стабильна, например, она подключена к интранету, то вы можете попробовать ее использовать.

Описание:Если вы используете tcp_tw_reuse, активируйте tcp_timestamps, иначе он будет недействительным.。

3. tcp_max_tw_buckets

Как следует из названияКонтролировать общее количество TIME_WAIT, В официальном документе веб-сайта говорится, что эта опция предназначена только для предотвращения некоторых простых DoS-атак и обычно не снижает ее искусственно. Если он будет уменьшен, система удалит избыточный TIME_WAIT, и журнал покажет: TCP: time wait bucket table overflow 。

Я должен напомнить всем, что все должно быть поменяно местами. Я видел, как кто-то установил "tcp_max_tw_buckets" на 0, то есть полностью отказался от TIME_WAIT. Это немного рискованно. Чтобы использовать пословицу Go, лучше переходить границу медленно.

Когда это появляется TCP: time wait bucket table overflow Когда, попробуйте увеличить следующие параметры:

Введение в RST:

В протоколе TCP RST означает сброс и используется для закрытия ненормальных соединений.При отправке пакета RST для закрытия соединения вам не нужно ждать, пока все пакеты данных в буфере будут отправлены, а пакеты данных в буфере будут напрямую отброшены и будет отправлен пакет RST. После получения пакета RST принимающей стороне не нужно отправлять пакет ACK для подтверждения.。

Несколько ситуаций, когда появляется RST:

Получать данные о закрытом сокете: Если сокет был закрыт, но все еще получает данные, то также будет сгенерирован RST.


Приглашаем всех желающих посетить открытый демо-урок «Практикум по написанию Ansible роли». На этом вебинаре участники вместе с экспертом будут писать, тестировать и отлаживать ansible роли. Это важно для тех, кто хочет автоматизировать настройку инфраструктуры, поскольку это один из инструментов, который это позволяет сделать. Сетевой стек — одна из самых запутанных вещей в Linux. И не только из-за сложности некоторых концепций и терминов, но и из-за изменения смысла некоторых параметров в разных версиях ядра. В этой статье приведена информация для ядра 2.2 и выше, а также, там где это возможно, указано различие между версиями вплоть до 5.5.

Очередь приема и netdev_max_backlog

Очередь ожидающих запросов на соединение и tcp_max_syn_backlog

Соединения создаются для SYN-пакетов из очереди приема и перемещаются в очередь ожидания (SYN Backlog Queue). Также соединение помечается как "SYN_RECV" и клиенту отправляется "SYN+ACK". Эти соединения не перемещаются в очередь установленных соединений ожидающих обработки accept() (accept queue) до тех пор, пока не будет получен и обработан соответствующий ACK. Максимальное количество соединений в этой очереди устанавливается параметром net.ipv4.tcp_max_syn_backlog .

Для просмотра очереди приема используйте команду netstat . На правильно настроенном сервере при нормальной нагрузке значение не должно быть больше 1. При большой нагрузке значение должно быть меньше размера очереди ожидания (SYN Backlog):

Если в состоянии "SYN_RECV" находятся много соединений, то можно также подстроить продолжительность нахождения SYN-пакета в этой очереди.

SYN Cookie

Повторы SYN+ACK

Что происходит, если SYN+ACK отправлен, но ответа ACK нет? В этом случае сетевой стек сервера повторит отправку SYN+ACK. Задержка между попытками вычисляется таким образом, чтобы обеспечить восстановление сервера. Если сервер получает SYN и отправляет SYN+ACK, но не получает ACK, то тайм-аут повторной передачи вычисляется по экспоненте (Exponental Backoff) и, следовательно, зависит от количества повторных попыток. Количество повторных попыток отправки SYN+ACK задается параметром ядра net.ipv4.tcp_synack_retries (по умолчанию равно 5). Повторные попытки будут через следующие интервалы: 1с, 3с, 7с, 15с, 31с. При шести попытках последняя будет примерно через 63 секунды после первой. Это позволяет удержать SYN-пакет в очереди ожидания более 60 секунд до истечения времени ожидания пакета. Если очередь SYN backlog мала, то не требуется большого количества соединений, чтобы возникла ситуация, когда полуоткрытые соединения никогда не завершатся и тогда никакие соединения не смогут быть установлены. Установите количество повторных попыток SYN+ACK равным 0 или 1, чтобы избежать такого поведения на высоконагруженных серверах.

Повторы SYN

Несмотря на то что повторные SYN-пакеты отправляются клиентом во время ожидания SYN+ACK, они могут влиять и на высоконагруженные серверы, работающие с прокси-соединениями. Например, сервер nginx, устанавливающий несколько десятков прокси-соединений к бэкенд-серверу, из-за всплесков трафика может на некоторое время перегрузить сетевой стек, а повторные попытки создадут дополнительную нагрузку на бэкэнд как в очереди приема, так и в очереди ожидания (SYN backlog). Это, в свою очередь, может повлиять на клиентские соединения. Повторные попытки SYN контролируются параметром net.ipv4.tcp_syn_retries (по умолчанию 5 или 6 в зависимости от дистрибутива). Ограничьте количество повторных попыток SYN до 0 или 1, чтобы не было долгих повторных попыток отправки в течение 63–130 с.

Более подробно о проблемах с клиентскими соединениями при обратном прокси-сервере читайте в статье Linux Kernel Tuning for High Performance Networking: Ephemeral Ports.

Очередь установленных соединений ожидающих принятия (accept queue) и somaxconn

Очередь запросов на соединение создает приложение, используя listen() и указывая размер очереди в параметре "backlog". Начиная с ядра 2.2 поведение этого параметра изменилось с максимального количества неоконченных запросов на соединение, которое может удерживать сокет, на максимальное количество полностью установленных соединений, ожидающих, пока они будут приняты. Как описано выше, максимальное количество неоконченных запросов на соединение теперь задается с помощью параметра ядра net.ipv4.tcp_max_syn_backlog .

somaxconn и параметр backlog в listen()

Хотя за размер очереди для каждого слушателя отвечает приложение, есть ограничение на количество соединений, которые могут находиться в очереди. Размером очереди управляют два параметра: 1) параметр backlog в функции listen() и 2) параметр ядра net.core.somaxconn , задающий максимальный размер очереди.

Значения по умолчанию для очереди

Значение по умолчанию для net.core.somaxconn берется из константы SOMAXCONN, которая в ядрах Linux вплоть до версии 5.3 имеет значение 128, но в 5.4 она была увеличена до 4096. Однако, на момент написания этой статьи, ядро 5.4 еще не очень распространено, поэтому в большинстве систем значение будет 128, если вы не модифицировали net.core.somaxconn.

Часто приложения для размера очереди по умолчанию используют константу SOMAXCONN, если этот размер не задается в конфигурации приложения. Хотя некоторые приложения устанавливают и свои значения по умолчанию. Например, в nginx размер очереди равен 511, который автоматически усекается до 128 в ядрах Linux до версии 5.3.

Изменение размера очереди

Многие приложения позволяют указывать размер очереди в конфигурации, указывая значение параметра backlog для listen() . Если приложение вызывает listen() со значением backlog , превышающим net.core.somaxconn, то размер очереди будет автоматически усечен до значения SOMAXCONN.

Потоки

Соединения и файловые дескрипторы

Системные ограничения

Любое сокетное соединение использует файловый дескриптор. Максимальное количество дескрипторов, которые могут быть созданы в системе, задается параметром ядра fs.file-max. Посмотреть количество используемых дескрипторов можно следующим образом:

Пользовательские ограничения

Помимо системного ограничения количества файловых дескрипторов, у каждого пользователя есть свои лимиты. Они настраиваются в системном файле limits.conf (nofile) или, при запуске процесса под управлением systemd, в unit-файле systemd (LimitNOFILE). Чтобы увидеть значение по умолчанию запустите:

Для systemd (на примере nginx):

Настройка

Для настройки системных ограничений установите параметр ядра fs.max-file в максимальное количество файловых дескрипторов, которое может быть в системе (с учетом некоторого буфера). Например:

Для настройки пользовательского лимита установите достаточно большое значение, чтобы хватило сокетам и файловым дескрипторам рабочих процессов (также с некоторым буфером). Пользовательские ограничения устанавливаются в /etc/security/limits.conf, в conf-файле в /etc/security/limits.d/ или в unit-файле systemd. Например:

Количество worker'ов

Аналогично файловым дескрипторам, количество worker'ов или потоков, которые может создать процесс, ограничено как на уровне ядра, так и на уровне пользователя.

Системные ограничения

Процессы могут создавать рабочие потоки. Максимальное количество потоков, которые могут быть созданы, задается параметром ядра kernel.threads-max . Для просмотра максимального и текущего количества потоков, выполняющихся в системе, запустите следующее:

Пользовательские ограничения

Есть свои ограничения и у каждого пользовательского процесса. Это также настраивается с помощью файла limits.conf (nproc) или unit-файла systemd (LimitNPROC). Для просмотра максимального количества потоков, которое может создать пользователь запустите:

Для systemd (на примере nginx):

Настройка

Как и в случае с nofile , ограничения для пользователей ( nproc ) устанавливаются в /etc/security/limits.conf, в conf-файле в /etc/security/limits.d/ или в unit-файле systemd. Пример с nproc и nofile :

Обратный прокси и TIME_WAIT

При большом всплеске трафика прокси-соединения, застрявшие в "TIME_WAIT", суммарно могут потреблять много ресурсов при закрытии соединения. Это состояние говорит, что клиент получил последний FIN-пакет от сервера (или вышестоящего worker'а) и находится в ожидании для корректной обработки пакетов. Время нахождения соединения в состоянии "TIME_WAIT" по умолчанию составляет 2 x MSL (Maximum Segment Length — максимальная длина сегмента), что составляет 2 x 60 с. В большинстве случаев это нормальное и ожидаемое поведение, и значение по умолчанию в 120 с вполне приемлемо. Однако много соединений в состоянии "TIME_WAIT" может привести к тому, что приложение исчерпает эфемерные порты для соединений к клиентскому сокету. В этом случае следует уменьшить FIN тайм-аут.

Управляет этим тайм-аутом параметр net.ipv4.tcp_fin_timeout . Рекомендуемое значение для высоконагруженных систем составляет от 5 до 7 секунд.

Собираем все вместе

Очередь приема (receive queue) должна быть рассчитана на обработку всех пакетов, полученных через сетевой интерфейс, не вызывая отбрасывания пакетов. Также необходимо учесть небольшой буфер на случай, если всплески будут немного выше, чем ожидалось. Для определения правильного значения следует отслеживать файл softnet_stat на предмет отброшенных пакетов. Эмпирическое правило — использовать значение tcp_max_syn_backlog, чтобы разрешить как минимум столько же SYN-пакетов, сколько может быть обработано для создания полуоткрытых соединений. Помните, что этот параметр задает количество пакетов, которое каждый процессор может иметь в своем буфере, поэтому разделите значение на количество процессоров.

Размер SYN очереди ожидания (SYN backlog queue) на высоконагруженном сервере должен быть рассчитан на большое количество полуоткрытых соединений для обработки редких всплесков трафика. Здесь эмпирическое правило заключается в том, чтобы установить это значение, по крайней мере, на максимальное количество установленных соединений, которое слушатель может иметь в очереди приема, но не выше, чем удвоенное количество установленных соединений. Также рекомендуется отключить SYN cookie, чтобы избежать потери данных при больших всплесках соединений от легитимных клиентов.

Очередь установленных соединений, ожидающих принятия (accept queue) должна быть рассчитана таким образом, чтобы в периоды сильного всплеска трафика ее можно было использовать в качестве временного буфера для установленных соединений. Эмпирическое правило — устанавливать это значение в пределах 20–25% от числа рабочих потоков.

Параметры

В этой статье были рассмотрены следующие параметры ядра:

И следующие пользовательские ограничения:

Заключение

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

Я запускаю определенную программу на linux, которая иногда аварийно завершается. Если после этого быстро открыть ее, она слушает сокет 49201, а не 49200, как в первый раз. netstat показывает, что 49200 находится в состоянии TIME_WAIT.

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

Ответ 1

/etc/init.d/networking restart

Transmission Control Protocol (TCP) разработан как двунаправленный, упорядоченный и надежный протокол передачи данных между двумя конечными точками (программами). В данном контексте термин « надежный » означает, что он будет повторно передавать пакеты, если они будут потеряны в процессе передачи. TCP гарантирует надежность, посылая обратно пакеты подтверждения (ACK) для одного или нескольких пакетов, полученных от аналога.

То же самое относится и к управляющим сигналам, таким как запрос/ответ на завершение. RFC793 определяет состояние TIME-WAIT следующим образом:

TIME-WAIT — представляет собой ожидание достаточного времени, чтобы убедиться, что удаленный TCP получил подтверждение своего запроса на разрыв соединения.

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

Назовем первого, кто объявляет о прекращении соединения, активным замыкающим, а другого — пассивным замыкающим. Когда активный доводчик посылает FIN, состояние переходит в FIN-WAIT-1. Затем он получает ACK на отправленный FIN, и состояние переходит в FIN-WAIT-2. Получив FIN также от пассивного доводчика, активный доводчик отправляет ACK на FIN, и состояние переходит в TIME-WAIT. Если пассивный доводчик не получил ACK на второй FIN, он повторно передает FIN-пакет.

RFC793 устанавливает TIME-OUT , равным удвоенному времени жизни максимального сегмента, или 2MSL. Поскольку MSL, максимальное время, в течение которого пакет может блуждать по и нтернету, установлено в 2 минуты, 2MSL равно 4 минутам. Поскольку нет ACK на ACK, активный досылатель не может сделать ничего, кроме как подождать 4 минуты, если он правильно придерживается протокола TCP/IP, на случай, если пассивный отправитель не получил ACK на свой FIN (теоретически).

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

Чтобы ответить на вопрос дословно : « Как принудительно закрыть сокет в TIME_WAIT? » , я буду придерживаться своего первоначального ответа:

/etc/init.d/networking restart

Практически говоря, я бы запрограммировал его так, чтобы он игнорировал состояние TIME-WAIT, используя опцию SO_REUSEADDR. Что именно делает SO_REUSEADDR?

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

Ответ 2

Насколько я знаю, нет способа принудительно закрыть сокет, кроме написания лучшего обработчика сигналов в вашей программе, но есть файл /proc, который управляет временем тайм - аута. Файл имеет следующий вид:

/proc/sys/net/ipv4/tcp_tw_recycle

и вы можете установить тайм-аут в 1 секунду, выполнив следующее:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle

Однако на этой странице содержится предупреждение о возможных проблемах с надежностью при установке этой переменной.

Существует также соответствующий файл:

/proc/sys/net/ipv4/tcp_tw_reuse

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

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


Ответ 3

Другой вариант — использовать опцию SO_LINGER с тайм-аутом 0. Таким образом, при закрытии сокета он будет закрыт принудительно, посылая RST, а не переходя в режим закрытия FIN/ACK. Это позволит избежать состояния TIME_WAIT и может быть более подходящим для некоторых случаев.

Ответ 4

Альтернативным решением может быть использование надежного прокси-сервера или программы переадресации портов, которая прослушивает порт 49200, а затем переадресует соединение на один из нескольких экземпляров вашей менее надежной программы, использующих разные порты. Например, HAPROXY.

Кстати, порт, через который вы подключаетесь, довольно высокий. Вы можете попробовать использовать неиспользуемый порт чуть выше диапазона 0-1024. Ваша система с меньшей вероятностью будет использовать более низкий номер порта в качестве него.

Мы будем очень благодарны

если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.

Читайте также: