LINUX.ORG.RU

Не доходит до accept при большом количестве соединений

 , , ,


0

2

Есть хитрый север(tcp, не блокирующие сокеты), живет на 3х портах через listen(sock, 5) на каждый, далее сокет загоняется в epoll(EPOLLET), как и все сокеты входящих соединений.
Все это обрабатывают 6 потоков, в которых живет epoll_wait, при появлении данных - сразу разбор пакетов и их обработка в принявшем же потоке.
И пока подключений мало 500-1000 - все работает нормально, но когда количество подключений подбирается к 2-2.5к до accept доходят уже не все входящие подключения, при этом запись/чтение в уже подключенные сокеты идет без проблем и задержек.
Смотрел через gdb - почти всегда все потоки висят в epoll_wait, т.е. это не из-за долгой обработки пакетов.
Если наглядно: сразу после accept добавил логов на свой ип, попробовал подключится - connect на клиенте прошел без проблем, на сервере же accept случился только секунд через 30, если вообще случился, чаще клиент отваливается раньше.
На случай чего - tcpdump на сервере показывает попытку подключения сразу.
Собственно что это может быть за колдунство и где его исправлять?

ulimit глянь. там по-умолчанию 1024 открытых файла обычно.

grondek ()
Ответ на: комментарий от grondek

Это я уже прошел когда-то.
RLIMIT_NOFILE стоит на максимум, т.е. 4096.

zlofenix ()

до accept доходят уже не все входящие подключения

замени

listen(sock, 5)

на listen(sock, 10)

anonymous ()
Ответ на: комментарий от zlofenix

а ты посчитай, может там все дескрипторы как раз упираются в 4096? цифра-то не такая уж и большая.

grondek ()
Ответ на: комментарий от grondek

Считал, не должно, т.к. суммарно сокетов 2.5к и уже это эффект в наличии.

zlofenix ()
Ответ на: комментарий от anonymous

Не помню пробовал или нет, если пробовал - не помогло.
Теоретически - т.к. все потоки висят в epoll_wait не должно упираться в это.

zlofenix ()

А Вы EPOLLET правильно обрабатываете? Попробуйте без этого флага сначала.

Sorcerer ★★★★★ ()
Последнее исправление: Sorcerer (всего исправлений: 1)
Ответ на: комментарий от anonymous

на linux, насколько я помню, вполне можно сделать listen(sock, 0) и должна быть бесконечная очередь. Но я не на 100% уверен.

Но если очередь переполнена - должно возвращаться ECONNREFUSED на клиенте - это можно отловить.

grondek ()
Ответ на: комментарий от Sorcerer

А как можно его не правильно обработать и в чем заключается правильность?

zlofenix ()
Ответ на: комментарий от zlofenix

т.к. все потоки висят в epoll_wait не должно упираться в это.

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

anonymous ()
Ответ на: комментарий от grondek

В этом и суть - connect проходит на клиенте, потом уже по таймеру клиент отключается, т.к. ничего не получает от сервера в ответ.

zlofenix ()
Ответ на: комментарий от zlofenix

Теоретически - т.к. все потоки висят в epoll_wait не должно упираться в это.

Посмотри netstat'ом размер очереди (Recv-Q), может накосячил где-то в обработчике и accept сокет не всегда находится в пуле.

mashina ★★★★★ ()
Ответ на: комментарий от zlofenix

А как можно его не правильно обработать

Например, можно оставить непрочитанными некоторые данные из дескриптора. В случае слушающего сокета можно вызвать accept() только один раз, хотя в очереди сокета уже 2 соединения, - это тоже неправильно (состояние сокета не изменилось, а значит, epoll не вернёт этот дескриптор снова).

Sorcerer ★★★★★ ()
Ответ на: комментарий от anonymous

Слушающие сокеты живут в 1й куче с входящими. Но судя по gdb потоки почти постоянно сидят на epoll_wait, а не на обработке данных, да и уже подключенные совершенно не тормозят. В epollе же нет приоритетов на подключенных и подключающихся.

zlofenix ()
Ответ на: комментарий от zlofenix

ты уж определись тогда: или

connect проходит на клиенте, потом уже по таймеру клиент отключается, т.к. ничего не получает от сервера в ответ.

или

до accept доходят уже не все входящие подключения

ибо пока на сервере accept() не отработает, на клиенте connect() не завершится

anonymous ()
Ответ на: комментарий от zlofenix

давай сюда кусок кода - цикл обаботки входящих содеинений.

grondek ()
Ответ на: комментарий от anonymous

ибо пока на сервере accept() не отработает, на клиенте connect() не завершится

4.2

Sorcerer ★★★★★ ()
Ответ на: комментарий от Sorcerer

Данные читаются в полном объеме. Как тогда отследить что там 2 ожидающих соединения? Не припоминаю чтоб где-то видел записи о подобном.

zlofenix ()
Ответ на: комментарий от zlofenix

Просто уберите флаг EPOLLET и попробуйте для начала.

Как тогда отследить что там 2 ожидающих соединения?

Вызывать accept() до опупения. Т.е. до EWOULDBLOCK. Или не использовать EPOLLET, тогда можно вызывать accept() и 1 раз.

Sorcerer ★★★★★ ()
Ответ на: комментарий от Sorcerer

4.2

ну да, не совсем так, немного наоборот
имелось ввиду, что если на клиенте connect() завершился, то без начала обработки accept() на сервере это обойтись не могло

anonymous ()
Ответ на: комментарий от anonymous

Тогда я не могу объяснить это, connect на клиенте блокируемый, но он проходит, а лог сразу после accept на сервере происходит с заметным опозданием.

zlofenix ()
Ответ на: комментарий от anonymous

что если на клиенте connect() завершился, то без начала обработки accept() на сервере это обойтись не могло

Это тоже не так.

Sorcerer ★★★★★ ()
Ответ на: комментарий от zlofenix

connect на клиенте блокируемый, но он проходит, а лог сразу после accept на сервере происходит с заметным опозданием.

accept() завершается позже завершения connect()?
разное время на клиенте и сервере, лог буферизируется где-то

anonymous ()
Ответ на: комментарий от Sorcerer

Это тоже не так.

ну-ка расскажи...
конечно, завершение connect() с -1 и errno==EINPROGRESS не считается

anonymous ()
Ответ на: комментарий от anonymous

После. Время правильное. Буферизация вывода в stdout вообще отключена, да и в файл сразу fflush после записи.

zlofenix ()
Ответ на: комментарий от anonymous

Заранее сообщаю что на клиенте -1 достаточно чтоб считать подключение не удавшимся. Но connect проходит с успехом.

zlofenix ()
Ответ на: комментарий от zlofenix

на сколько после? так и должно быть «после»; проблема то, видимо, в «гораздо»? или в чем?

anonymous ()
Ответ на: комментарий от anonymous

До 40 секунд, дальше уже клиент по таймеру отключается.

zlofenix ()

На случай чего - tcpdump на сервере показывает попытку подключения сразу.

т.е SYN приходит сразу? смотри дальше когда уходит SYN+ACK, а потом еще когда от клиента приходит ACK
если последний ACK приходит тоже сразу, то проблема с его обработкой на сервере — вторая фаза accept(), если ACK задерживается, то проблема на клиенте или в транспорте

anonymous ()
Ответ на: комментарий от Sorcerer

Проверил, при запуске сервера сразу обнаружился сокет с 2 ожидающими подключениями, посмотрим что будет вечером, обычно вечером подключений больше идет. Добра.

zlofenix ()
Ответ на: комментарий от zlofenix

Обновил логи - даже до 6 подключений в 1 событии дошло уже.

zlofenix ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.