описание проблемы
После запуска распределенной транзакции Lottor в тестовой среде в течение определенного периода времени клиент Lottor не может подключиться к серверу Lottor. После расследования было обнаружено, что основная проблема заключалась в том, что клиент Lottor не мог получить информацию о кластере сервера Lottor.
Lottor Server запускает два порта: 9666 — порт контейнера Tomcat, а 9888 — порт сетевого сервера. Проверьте состояние порта с помощью следующей команды:
netstat -apn
порт службы netty
netstat -apn|grep 9888
Сначала проверьте порт сервера netty, соединение нормальное и не имеет ничего общего с проблемой, которую мы описали выше. Исключите подключение службы netty.
Порт контейнера Tomcat
Далее проверяем состояние порта контейнера Tomcat:
netstat -apn|grep 9666
Обнаружено большое количество соединений с состояниями FIN_WAIT2 и CLOSE_WAIT.
Кроме того, вы можете просмотреть текущее количество подключений с помощью следующей команды:
netstat -apn|grep 9666 | wc -l
Если углубиться дальше, можно увидеть, что количество подключений в состояниях FIN_WAIT2 и CLOSE_WAIT сопоставимо.
ПТС махнул четыре раза
Коммуникационный клиент и сервер устанавливают TCP-соединение через трехстороннее рукопожатие. Когда передача данных завершена, обе стороны могут разорвать соединение. В начале и клиент, и сервер находятся в состоянии ESTABLISHED, затем клиент активно выключается, а сервер выключается пассивно.
Активное отключение соединения может происходить как на стороне клиента, так и на стороне сервера. Обычно используются три состояния: ESTABLISHED указывает на связь, TIME_WAIT указывает на активное завершение работы, а CLOSE_WAIT указывает на пассивное завершение работы.
ESTABLISHED
В начале и клиент, и сервер находятся в состоянии ESTABLISHED, затем клиент или сервер инициируют активное завершение работы, а другой конец пассивно закрыт.
FIN_WAIT1
Когда одна сторона получает сигнал от приложения на отключение, она отправляет дейтаграмму FIN для активного отключения, и соединение переходит в состояние FIN_WAIT1, а управление соединением переходит к ядру, и программа больше не будет его обрабатывать. При нормальных обстоятельствах состояние обработки соединения FIN_WAIT1 длится только в течение короткого периода времени.
CLOSE_WAIT
После того, как пассивно закрытый конец получает пакет FIN, его состояние CLOSE_WAIT означает, что он пассивно закрыт.
FIN_WAIT2
Когда запрос FIN активной стороны отключения отправляется и соответствующий запрос ACK успешно получен, он переходит в состояние FIN_WAIT2. На самом деле состояния FIN_WAIT1 и FIN_WAIT2 ожидают дейтаграмму FIN другой стороны. Когда TCP поддерживает это состояние, другая сторона может никогда не отключиться, что приведет к сохранению соединения.
TIME_WAIT
Из приведенной выше диаграммы перехода состояния закрытия соединения TCP видно, что сторона, которая активно закрылась, перейдет в состояние TIME_WAIT после отправки сообщения подтверждения (ACK) в сообщение FIN другой стороны. Состояние TIME_WAIT также известно как состояние 2MSL. Значение MSL — это максимальное время жизни пакета в сети. В результате четыре кортежа (IP-адрес и порт клиента, IP-адрес и номер порта сервера), определяющие это соединение, не могут использоваться, пока соединение TCP ожидает соединения 2MSL.
Анализ причин
После представления соответствующего состояния четырех взмахов рук TCP в предыдущем разделе мы проанализируем, при каких обстоятельствах соединение находится в состоянии CLOSE_WAIT? В случае пассивного закрытия соединения соединение находится в состоянии CLOSE_WAIT, когда FIN получен, но собственный FIN не отправлен. Вообще говоря, продолжительность состояния CLOSE_WAIT должна быть короткой, как и состояние SYN_RCVD. Однако в некоторых особых случаях соединение будет находиться в состоянии CLOSE_WAIT в течение длительного времени.
Есть много явлений close_wait, основная причина в том, что другая сторона в некоторых случаях закрывает соединение сокета, но другой конец не закрывает соединение, потому что он читает и пишет. Код должен оценить сокет.Как только он прочитает 0, разорвите соединение, чтение вернет отрицательный результат, проверьте errno, и если это не СНОВА, разъедините.
Файловые дескрипторы, выделяемые пользователю Linux, ограничены, и если сохраняются два состояния TIME_WAIT и CLOSE_WAIT, это означает, что соответствующее количество каналов всегда будет занято. запросы не могут быть обработаны. , за которыми следует большое количество исключений Too Many Open Files, что приводит к сбою tomcat. Посмотреть решение слишком много TIME_WAITСлишком много TIME_WAIT.
Распространенные причины ошибок
В принципе, поскольку Socket сервера не вызывает close, когда клиент закрылся, соединение сервера находится в "приостановленном" состоянии, в то время как клиент находится в состоянии ожидания ответа. Типичной особенностью этой проблемы является то, что один конец находится в состоянии FIN_WAIT2, а другой конец — в состоянии CLOSE_WAIT. Конкретно:
1. Соединение не закрывается на уровне кода.Например, в блоке finally не прописан закрывающий код для закрытия.Если в программе возникнет исключение, то закрывающий код будет пропущен.Естественно инструкция не выдается на закрыть соединение. Соединение всегда управляется программой, и ядро не имеет права его обрабатывать. , естественно, запрос FIN не выдается, в результате чего соединение все время находится в состоянии CLOSE_WAIT.
2. Ответ программы слишком медленный.Например, когда две стороны общаются друг с другом, когда клиент запрашивает, что сервер не может получить ответ, соединение разрывается и запрос инициируется повторно.В результате, сервер был занят бизнес-процессами и не успел закрыть соединение. Эта ситуация также может вызвать эту проблему.
Проблемы в лото
В Lottor клиент периодически обновляет локально сохраненную адресную информацию сервера Lottor, в частности, каждые 60 секунд, и получает результат через запрос HttpClient. Основываясь на информации, найденной в Интернете, и приведенном выше анализе, автор сначала пытается отключить периодическое обновление и наблюдать за количеством подключений к порту 9666 сервера Lottor. Количество подключений, которые росли линейно, прежде чем остановились, и изначально была обнаружена основная причина проблемы.
Сервер A является сервером сканера. Он использует простой HttpClient для запроса apache на сервере ресурсов B для получения файловых ресурсов. При нормальных обстоятельствах, если запрос выполнен успешно, сервер A будет активно отправлять запрос на закрытие соединения после обхода ресурса. , на этот раз нужно активно закрыть соединение, мы видим, что состояние соединения сервера А — TIME_WAIT. Что делать, если возникает исключение? Предполагая, что запрошенный ресурс не существует на сервере B, тогда сервер B выдаст запрос на закрытие соединения в это время.Сервер A пассивно закрывает соединение.Если сервер A пассивно закрывает соединение, программист забывает позволить HttpClient освободить соединение. соединение, что вызовет состояние CLOSE_WAIT.
Сценарий автора такой же, как и в приведенной выше ситуации.Решение этой проблемы заключается в том, что мы должны напрямую вызывать разрыв соединения при обнаружении исключения, чтобы предотвратить продолжение состояния CLOSE_WAIT. Дело можно найти вПул соединений HttpClient выдает много ConnectionPoolTimeoutException: тайм-аут, ожидающий устранения неполадок исключения соединения. Более поздний метод улучшения, предложенный автором, состоит в том, чтобы переписать логику этой части, которая вызывается и выполняется Spring Cloud FeignClient, чтобы избежать утомительных операций, таких как предыдущий запрос балансировки нагрузки.