У меня есть странная проблема с сервером, принимающим соединения TCP. Даже при том, что обычно существует некоторое ожидание процессов в некотором объеме соединений, это зависает.
Долгая версия:
Сервер записан в Perl и связывает a $srv
сокет с повторным использованием отмечает и слушает == 5. Впоследствии, это разветвляется в 10 процессов с циклом $clt=$srv->accept(); do_processing($clt); $clt->shutdown(2);
Клиент, записанный в C, также очень прост - он отправляет некоторые строки, затем получает все доступные строки и делает a shutdown(sockfd, 2);
Нет ничего, что асинхронное продолжение и в конце и отправляет и принимает очереди, пусты (как сообщается netstat
).
Соединения длятся только ~20ms. Все клиенты ведут себя тот же путь, та же реализация, и т.д. Теперь скажем, я принимаю X
соединения от клиента 1 и другой X
от клиента 2. Процессы все еще сообщают, что они неактивны все время. Если я добавляю другого X
соединения от клиента 3, внезапно серверные процессы начинают зависать сразу после принятия. Первая вещь блокирования они делают после accept();
while (<$clt>) ...
- но они уже не получают данных (на первой попытке). Внезапно все 10 процессов находятся в этом состоянии и не прекращают ожидать. На strace
, серверные процессы, кажется, держатся read()
, который имеет смысл.
Существуют загрузки соединений в TIME_WAIT
состояние, принадлежащее тому серверу (~100, когда проблема начинает проявлять), но это могло бы быть отвлекающим маневром.
Что могло происходить здесь?
Еще после некоторого анализа: оказалось, что клиент был виновным, не закрывая предыдущие соединения правильно прежде, чем попробовать следующее. Серверам в начале списка выравнивания нагрузки оставили устаревшие соединения.
Скачки, а затем пауза на длительное время (около двух минут), а затем снова ? Если это так, возможно, в вашей системе установлен недостаточно высокий лимит максимального количества открытых файлов.
Это, вероятно, не решение вашей проблемы, но может решить проблему, с которой вы столкнетесь в будущем: не забудьте закрыть () сокеты, когда закончите! shutdown () отключит поток, но по-прежнему съест файловый дескриптор.
Поскольку вы сказали, что strace показывает процессы, застрявшие в read (), ваша проблема, похоже, в том, что клиент не отправляет данные, которые вы ожидаете от него. Вы должны либо исправить своего клиента, либо добавить alarm () к процессам сервера, чтобы они могли пережить мертвых клиентов.