epoll in Linux
От: maks1180  
Дата: 07.06.24 10:09
Оценка:
Есть сетевое приложение (работает через epoll) которое обслуживает много TCP соединений (иногда более 100 тыс), большинство в режиме ожидания и только пинг 1 раз в минуту делают.
Ранее добавял сокеты через epoll_ctl с флагами EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLET

Но EPOLLET обязывает почитывать все содержимое сокета, иначе нотификации EPOLLIN больше не будет пока не придёт новый пакет.
Если клиент большой трафик посылает, скажем 500 Мбит/с, то если читать его данные в цикле, то остальные клиенты будут ждать и будут лаги.
Поэтому я решил избавиться от EPOLLET, но тогда EPOLLOUT будет постоянно приходить, поэтому пришлось убрать и EPOLLOUT.
А EPOLLOUT я теперь выборочно добавляю и снимаю [через epoll_ctl(EPOLL_CTL_MOD)] для тех сокетов для которых send() не смог отправить все данные.
Но проблема в том что epoll_ctl накладная функции, и чем больше сокетов в epoll тем она медленнее работает (видимо поиск по дереву, не очень хорошо реализован).

Может я что-то не понимаю ? Понимаю, что у меня типовая задача и она должна как-то проще реализовываться
Кажется что мне нужно EPOLLIN без EPOLLET + EPOLLOUT с EPOLLET, но как это реализовать не дергая постоянно epoll_ctl ?
===============================================
(реклама, удалена модератором)
Отредактировано 07.06.2024 10:10 maks1180 . Предыдущая версия .
Re: epoll in Linux
От: andrey.desman  
Дата: 07.06.24 10:38
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Может я что-то не понимаю ? Понимаю, что у меня типовая задача и она должна как-то проще реализовываться


А чем не подходит ready list, который в самой же доке и упоминается?
Re[2]: epoll in Linux
От: maks1180  
Дата: 07.06.24 11:49
Оценка:
AD>А чем не подходит ready list, который в самой же доке и упоминается?

Не понял вашего вопроса, как получить то ready list ?
Мне кажется он внутри ядра находится и его нельзя получить, кроме как epoll_wait() который я и использую.
===============================================
(реклама, удалена модератором)
Re[3]: epoll in Linux
От: andrey.desman  
Дата: 07.06.24 12:16
Оценка:
Здравствуйте, maks1180, Вы писали:

AD>>А чем не подходит ready list, который в самой же доке и упоминается?


M>Не понял вашего вопроса, как получить то ready list ?

M>Мне кажется он внутри ядра находится и его нельзя получить, кроме как epoll_wait() который я и использую.

Речь про свой, разумеется. Как-то так:

for (;;) {
    int timeout = ready_list.empty() ? infinity : 0;
    epoll_wait(events, timeout);
    append_to_ready_list(events);

    for (auto& descriptor : ready_list) {
        if (process_descriptor_bw_constrained(descriptor) == EAGAIN)
            ready_list.erase(descriptor);
    }
}
Re[4]: epoll in Linux
От: maks1180  
Дата: 07.06.24 13:10
Оценка:
Теперь понял, думал я на этим. Но при append_to_ready_list() нужно проверять нет ли его уже, а при удаление сокета из epoll нужно удалять из ready_list.
Код что вы привели это рабочий или для примера написали ?
Если рабочий, с насколько большой нагрузкой он работает ?
===============================================
(реклама, удалена модератором)
Re: epoll in Linux
От: reversecode google
Дата: 07.06.24 14:11
Оценка:
M>Если клиент большой трафик посылает, скажем 500 Мбит/с, то если читать его данные в цикле, то остальные клиенты будут ждать и будут лаги.

проконсультирую за $5k
о том что надо использовать threads
Re: epoll in Linux
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 10.06.24 05:46
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Есть сетевое приложение (работает через epoll) которое обслуживает много TCP соединений (иногда более 100 тыс), большинство в режиме ожидания и только пинг 1 раз в минуту делают.

M>Ранее добавял сокеты через epoll_ctl с флагами EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLET

M>Но EPOLLET обязывает почитывать все содержимое сокета, иначе нотификации EPOLLIN больше не будет пока не придёт новый пакет.

M>Если клиент большой трафик посылает, скажем 500 Мбит/с, то если читать его данные в цикле, то остальные клиенты будут ждать и будут лаги.

По получению сокета из epoll_wait ставить свой внутренний флаг о том, что этот сокет надо постоянно читать, пока не выдает EAGAIN. Кажется, очевидно. Дальше — не циклиться постоянно на этом сокете, а читать, например, порциями по несколько килобайт за цикл, и ставить таймаут 0, пока есть хоть один такой сокет с таким флагом.

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

M>Поэтому я решил избавиться от EPOLLET, но тогда EPOLLOUT будет постоянно приходить, поэтому пришлось убрать и EPOLLOUT.

M>А EPOLLOUT я теперь выборочно добавляю и снимаю [через epoll_ctl(EPOLL_CTL_MOD)] для тех сокетов для которых send() не смог отправить все данные.

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

M>Но проблема в том что epoll_ctl накладная функции, и чем больше сокетов в epoll тем она медленнее работает (видимо поиск по дереву, не очень хорошо реализован).


M>Может я что-то не понимаю ? Понимаю, что у меня типовая задача и она должна как-то проще реализовываться

M>Кажется что мне нужно EPOLLIN без EPOLLET + EPOLLOUT с EPOLLET, но как это реализовать не дергая постоянно epoll_ctl ?

Таки внутренний флаг, см. выше.

Ну и резать группы сокетов между нитями. Если там сверхлинейные затраты на поиск в ядерных структурах, это существенно сэкономит на данном поиске.
The God is real, unless declared integer.
Re[2]: epoll in Linux
От: maks1180  
Дата: 11.06.24 22:02
Оценка:
N>А ещё достаточно разумно рядом подсказывают, что именно такие потоки можно перекидывать в отдельные нити и пусть те себе занимаются, пока не кончится. Потом можно и вернуть в основной контроль.
Это сильно усложняет ПО, когда вместо 1-го потока будет несколько, нужно добавлять синхронизацию, спинлоки например. Это может в некоторых случаях замедлить ПО. Вероятность внести багу — огромная.

M>>Поэтому я решил избавиться от EPOLLET, но тогда EPOLLOUT будет постоянно приходить, поэтому пришлось убрать и EPOLLOUT.

M>>А EPOLLOUT я теперь выборочно добавляю и снимаю [через epoll_ctl(EPOLL_CTL_MOD)] для тех сокетов для которых send() не смог отправить все данные.

N>Или для которых нечего отправлять?

N>Как раз если есть что отправлять, то его надо бы оставлять.

Для которых send() не смог отправить все данные, устанавливаю флаг EPOLLOUT, а когда больше нечего отправлять снимаю флаг EPOLLOUT

M>>Но проблема в том что epoll_ctl накладная функции, и чем больше сокетов в epoll тем она медленнее работает (видимо поиск по дереву, не очень хорошо реализован).


M>>Может я что-то не понимаю ? Понимаю, что у меня типовая задача и она должна как-то проще реализовываться

M>>Кажется что мне нужно EPOLLIN без EPOLLET + EPOLLOUT с EPOLLET, но как это реализовать не дергая постоянно epoll_ctl ?

N>Таки внутренний флаг, см. выше.


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

N>Ну и резать группы сокетов между нитями. Если там сверхлинейные затраты на поиск в ядерных структурах, это существенно сэкономит на данном поиске.

Они может и линейные затраты, но поиск по бинарному дереву должен быть ~lg(N).
===============================================
(реклама, удалена модератором)
статья про epoll
От: maks1180  
Дата: 12.06.24 00:47
Оценка:
Прочитал полезную статью про epoll, но что-то не совсем понятно, кажется что перевод был машинный и с ошибками.
https://habr.com/ru/companies/ruvds/articles/523946/ часть 1
https://habr.com/ru/companies/ruvds/articles/526582/ часть 2
https://habr.com/ru/companies/ruvds/articles/526802/ часть 3
https://habr.com/ru/companies/ruvds/articles/527174/ часть 4

Вот что я понял из статьи:

1) epoll_ctl() региструрует callback функцию которая собирает event от файлового дескриптора, который передали.
2) при вызове epoll_wait(), обрабатывает все event которые были получены через callback функцию, составляет ready list список.
Вызывает vfs_poll() для каждого файла из ready list, что-бы проверить действительно ли он имеет available for read или available for write ?
если имеет, то отдаёт пользователю.
3) если не установлен EPOLLET, то добавляем в ready list, для следующего вызова epoll_wait().

Или по другому, но тот же смысл:
1) при EPOLLET проверяет файл при добавлении или если были события по нему с момента последнего вызова epoll_wait
2) при !EPOLLET проверяет файл, как при п.1 плюс еще если в прошлый вызов epoll_wait файл попал в ready list

Вот это интересно, получается с EPOLLET будет быстрее работать ?

Что делает vfs_poll ? Где можно информацию почитать, кроме исходников ?

Какие события для TCP сокетов, передаются через callback функцию ?
===============================================
(реклама, удалена модератором)
Отредактировано 12.06.2024 1:25 maks1180 . Предыдущая версия . Еще …
Отредактировано 12.06.2024 0:48 maks1180 . Предыдущая версия .
Re: статья про epoll
От: reversecode google
Дата: 12.06.24 07:44
Оценка: -1
за $15к покажу места в исходниках линукс ядра

а вообще закрывайте свой не до бизнес Ammyy Admin
программирование это очень сложно
вероятность что вы не правильно напишите программу очень велика
а последствия для пользователя чреваты большими проблемами
вплоть до форматирования его жесткого диска

или вы готовы компенсировать каждому пользователю потерю его информации из за ваших скудных познаний в программировании?
Отредактировано 12.06.2024 9:32 Великий Реверс . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.