TCP & libuv
От: maks1180  
Дата: 26.11.22 16:51
Оценка:
Пишу сервер приложение на с++ через libuv для работы с большим количеством TCP клиентов, поэтому ресурсы важны.
Я в libuv пока не силён, но на сколько я понял, для отправки по TCP нужно использовать uv__write и если сокет пока не может принять данные, то внутри libuv появляется очередь на запись.
И если 100 раз я вызвал uv__write пока сокет недоступен для записи, то будет очередь из 100 запросов за запись и потом вызовется 100 раз функции send().
Это не оптимальное решение. Было был лучше так: Я сам строю очередь на запись, а libuv вызывает мою callback функцию когда сокет доступен на запись и я вызываю send() и сам уменьшаю очередь на запись.
Можно ли в libuv сделать так ?
===============================================
(реклама, удалена модератором)
Re: TCP & libuv
От: Pzz Россия https://github.com/alexpevzner
Дата: 26.11.22 19:56
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Пишу сервер приложение на с++ через libuv для работы с большим количеством TCP клиентов, поэтому ресурсы важны.


А большое количество — это сколько? И какова совокупная нагрузка/нагрузка по клиенту?
Re[2]: TCP & libuv
От: maks1180  
Дата: 26.11.22 20:09
Оценка:
M>>Пишу сервер приложение на с++ через libuv для работы с большим количеством TCP клиентов, поэтому ресурсы важны.

Pzz>А большое количество — это сколько? И какова совокупная нагрузка/нагрузка по клиенту?


около 300 тыс соединений. Нагрузка пока не известна, но нужно написать максимально хорошо, чем больше выдержит тем лучше.
Пока такая задача.
===============================================
(реклама, удалена модератором)
Re[3]: TCP & libuv
От: Pzz Россия https://github.com/alexpevzner
Дата: 26.11.22 21:04
Оценка:
Здравствуйте, maks1180, Вы писали:

M>около 300 тыс соединений. Нагрузка пока не известна, но нужно написать максимально хорошо, чем больше выдержит тем лучше.

M>Пока такая задача.

300K — это много.

Ну в принципе, у тебя есть такой API: https://github.com/libuv/libuv/blob/v1.x/docs/src/poll.rst

Я только не очень понимаю, зачем тебе libuv, если почти всю ее работу ты собираешься делать сам, и низкоуровнего сокетного API вроде как не боишься.
Re[4]: TCP & libuv
От: maks1180  
Дата: 26.11.22 23:00
Оценка:
Pzz>300K — это много.
95% будут в режиме ожидания находиться и только 1 раз в минуту отправлять маленькие пакеты.

Pzz>Ну в принципе, у тебя есть такой API: https://github.com/libuv/libuv/blob/v1.x/docs/src/poll.rst

Спасибо, попробую.

Pzz>Я только не очень понимаю, зачем тебе libuv, если почти всю ее работу ты собираешься делать сам, и низкоуровнего сокетного API вроде как не боишься.

Но не всю, а только отправку по сигналу от libuv хочу сделать. Конечно можно самому разобраться с epoll (на Linux) и completion port (на Windows). Но зачем если libuv хорошо протестирована ?
===============================================
(реклама, удалена модератором)
Re[5]: TCP & libuv
От: maks1180  
Дата: 27.11.22 02:33
Оценка:
Pzz>>Я только не очень понимаю, зачем тебе libuv, если почти всю ее работу ты собираешься делать сам, и низкоуровнего сокетного API вроде как не боишься.
M>Но не всю, а только отправку по сигналу от libuv хочу сделать. Конечно можно самому разобраться с epoll (на Linux) и completion port (на Windows). Но зачем если libuv хорошо протестирована ?

Подебажил я по исходникам libuv — очень много всего нагорожено. Что-бы сделать UPDATE-ON-FLY с libuv нужно будет долго возиться. Действительно проще самому реализовать работу с epoll и completion port.

UPDATE-ON-FLY — это когда приложение передаёт все дескрипторы и всю информацию своей новой версии и та начинает работать не разрывая соединения. Клиент вообще не замечает такого обновления. Мы делали эксперимент и с 300 тыс TCP клиентов, апдей занял около 500мс, т.е. клиенты максимум получали доп задержку в 500мс и не замечали обновления.
===============================================
(реклама, удалена модератором)
Re[6]: TCP & libuv
От: flаt  
Дата: 27.11.22 05:38
Оценка:
Здравствуйте, maks1180, Вы писали:

M>UPDATE-ON-FLY — это когда приложение передаёт все дескрипторы и всю информацию своей новой версии и та начинает работать не разрывая соединения.


Насколько я помню, это в винде нельзя было сделать — передать сокет другому процессу.
Re[5]: TCP & libuv
От: Pzz Россия https://github.com/alexpevzner
Дата: 27.11.22 10:57
Оценка: +1
Здравствуйте, maks1180, Вы писали:

Pzz>>300K — это много.

M>95% будут в режиме ожидания находиться и только 1 раз в минуту отправлять маленькие пакеты.

А протокол самодельный?

Pzz>>Я только не очень понимаю, зачем тебе libuv, если почти всю ее работу ты собираешься делать сам, и низкоуровнего сокетного API вроде как не боишься.

M>Но не всю, а только отправку по сигналу от libuv хочу сделать. Конечно можно самому разобраться с epoll (на Linux) и completion port (на Windows). Но зачем если libuv хорошо протестирована ?

А тебе так уж важно, чтобы работало и на linux и в венде?

Дело в том, что у линуха с вендой модель асинхронного ввода-вывода очень разная. На линухе мы дожидаемся готовности сокета (т.е., наличия у него места в буфере), потом туда делаем send(), сокет копирует данные в свой буфер и отправляет в сеть по мере возможности, а нас уведомляет, когда в него можно подпихнуть следущую порцию данных.

Венда же, наоборот, мы ей сразу даем порцию данных, а она сообщает, когда они отправлены. Это называется overlapped i/o.

На венде трудно сэмулировать линуксное поведение достаточно хорошо, чтобы массштабировалось на 300К сокетов. Проще наоборот, эмулировать вендовое поведение на линуксе. Отсюда очереди, которые в венде просто превратятся в overlapped i/o с completion port (т.е., очередью будет управлять система), а на линуксе будут управляться програмно. Но зато высокоуровневый API один и тот же.

Если учесть, что основная серверная платформа телерь линукс, может вообще, ну ее нафиг, эту венду?
Re[7]: TCP & libuv
От: maks1180  
Дата: 27.11.22 22:01
Оценка:
M>>UPDATE-ON-FLY — это когда приложение передаёт все дескрипторы и всю информацию своей новой версии и та начинает работать не разрывая соединения.

F>Насколько я помню, это в винде нельзя было сделать — передать сокет другому процессу.


Я это делал в Linux. В Windows тоже вроже можно через DuplicateHandle
===============================================
(реклама, удалена модератором)
Re: TCP & libuv
От: maks1180  
Дата: 27.11.22 22:06
Оценка:
M>И если 100 раз я вызвал uv__write пока сокет недоступен для записи, то будет очередь из 100 запросов за запись и потом вызовется 100 раз функции send().

Подебажил я исходники libuv в Линуксе она вызывает не send, а write/writev. Возможно она сможет объединить много запросов на запись через 1 вызов writev, но для этого ей нужно выделить память, что-бы собрать все запросы для 1 вызова writev — не уверен что она так будет делать.

Почему write, а не send ? Кто из них быстрее будет работать ?
===============================================
(реклама, удалена модератором)
Re[6]: TCP & libuv
От: maks1180  
Дата: 27.11.22 22:18
Оценка:
Pzz>>>300K — это много.
M>>95% будут в режиме ожидания находиться и только 1 раз в минуту отправлять маленькие пакеты.

Pzz>А протокол самодельный?

Да

Pzz>А тебе так уж важно, чтобы работало и на linux и в венде?

Для Windows не особо важно, но удобнее тестировать общий код на Windows и может пригодиться кому-нибудь такое решение.

Pzz>Дело в том, что у линуха с вендой модель асинхронного ввода-вывода очень разная. На линухе мы дожидаемся готовности сокета (т.е., наличия у него места в буфере), потом туда делаем send(), сокет копирует данные в свой буфер и отправляет в сеть по мере возможности, а нас уведомляет, когда в него можно подпихнуть следущую порцию данных.

Pzz>Венда же, наоборот, мы ей сразу даем порцию данных, а она сообщает, когда они отправлены. Это называется overlapped i/o.

В любом случаи я должен хранить буффер для отправки сам (для libuv тоже), и поэтому для отправки я не вижу проблем.
Вызываю send и жду, в Linux когда статус сокета измениться, в Windows когда операция завершиться.

Для чтения, в Windows нужно заранее выделить буфер. Вот тут отличия, так как зараняя выделить существенный буфер для 300К клиентов — это накладно.
А общий буфер для всех клиентов в Windows так наверно нельзя делать ? Или можно если только 1 поток будет работать с IoCompletionPort ?
Если нельзя, попробую выделить 1 байт и потом уже дочитать вторым вызовом recv().
Есть ещё какие-то варианты в Windows, без существенного буфера для каждого клиента ?

Pzz>Если учесть, что основная серверная платформа телерь линукс, может вообще, ну ее нафиг, эту венду?

Может и откажусь. Но пока вроде для моих задач, можно на обоих сделать.
===============================================
(реклама, удалена модератором)
Отредактировано 27.11.2022 22:22 maks1180 . Предыдущая версия . Еще …
Отредактировано 27.11.2022 22:19 maks1180 . Предыдущая версия .
Re[7]: TCP & libuv
От: Pzz Россия https://github.com/alexpevzner
Дата: 27.11.22 22:23
Оценка:
Здравствуйте, maks1180, Вы писали:

Pzz>>А протокол самодельный?

M>Да

С самодельными протоколами в реальной обстановке хлопот не оберешься...

M>Для чтения, в Windows нужно заранее выделить буфер. Вот тут отличия, так как зараняя выделить существенный буфер для 300К клиентов — это накладно.

M>А общий буфер для всех клиентов в Windows так наверно нельзя делать ? Или можно если только 1 поток будет работать с IoCompletionPort ?

Нет, нельзя. Completion port — это очередь статусов отработанных запросов. Сами запросы работают независимо от потока, который выгребает completion port.

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


Не очень хорошая идея. Тебе придется делать два вызова на каждую порцию данных.

M>Есть ещё какие-то варианты в Windows, без существенного буфера для каждого клиента ?


Насколько я помню, таких, которые умеют работать с completion port, других больше нет.
Re[2]: TCP & libuv
От: Pzz Россия https://github.com/alexpevzner
Дата: 27.11.22 22:24
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Почему write, а не send ? Кто из них быстрее будет работать ?


Более-менее одинаково. send добавляет флаги, writev позволяет собрать вместе несколько буферов без промежуточного копирования.
Re[8]: TCP & libuv
От: maks1180  
Дата: 28.11.22 00:08
Оценка:
M>>Есть ещё какие-то варианты в Windows, без существенного буфера для каждого клиента ?

Pzz>Насколько я помню, таких, которые умеют работать с completion port, других больше нет.


Если сделать через message-based notification (WSAAsyncSelect) и отдельное окно для этих целей.
Насколько это решение будет выдерживать большие нагрузки ?
Это решение будет аналогично epoll ? т.е.информировать когда у сокета есть данные для чтения, или он готов принять данные для отправки.
===============================================
(реклама, удалена модератором)
Re[8]: TCP & libuv
От: maks1180  
Дата: 28.11.22 00:10
Оценка:
Pzz>>>А протокол самодельный?
M>>Да

Pzz>С самодельными протоколами в реальной обстановке хлопот не оберешься...


Каких например ?
Много лет уже работают протоколы самодельные поверх TCP.
===============================================
(реклама, удалена модератором)
Re: TCP & libuv
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 28.11.22 05:48
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Пишу сервер приложение на с++ через libuv для работы с большим количеством TCP клиентов, поэтому ресурсы важны.

Собери буст.асио либо вообще gRPC возьми. У тебя не такие серьёзные нагрузки чтобы прямо по хардкору развлекаться с сокетами, uv и epool.
Sic luceat lux!
Re: TCP & libuv
От: Mr.Delphist  
Дата: 28.11.22 13:00
Оценка:
Здравствуйте, maks1180, Вы писали:

M>И если 100 раз я вызвал uv__write пока сокет недоступен для записи, то будет очередь из 100 запросов за запись и потом вызовется 100 раз функции send().

M>Это не оптимальное решение. Было был лучше так: Я сам строю очередь на запись, а libuv вызывает мою callback функцию когда сокет доступен на запись и я вызываю send() и сам уменьшаю очередь на запись.

Вроде бы Nagle-алгоритм включен по умолчанию, поэтому переживать насчёт рукопашного уменьшения количества send не нужно?

Ну и в целом worth-to-read:
https://www.extrahop.com/company/blog/2016/tcp-nodelay-nagle-quickack-best-practices/
Re[8]: TCP & libuv
От: flаt  
Дата: 28.11.22 14:37
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Я это делал в Linux. В Windows тоже вроже можно через DuplicateHandle


Точно, WSADuplicateSocket
Re[2]: TCP & libuv
От: maks1180  
Дата: 28.11.22 16:48
Оценка:
MD>Вроде бы Nagle-алгоритм включен по умолчанию, поэтому переживать насчёт рукопашного уменьшения количества send не нужно?

Я его отключаю.
===============================================
(реклама, удалена модератором)
Re[2]: TCP & libuv
От: maks1180  
Дата: 28.11.22 16:57
Оценка:
M>>Пишу сервер приложение на с++ через libuv для работы с большим количеством TCP клиентов, поэтому ресурсы важны.
K>Собери буст.асио либо вообще gRPC возьми. У тебя не такие серьёзные нагрузки чтобы прямо по хардкору развлекаться с сокетами, uv и epool.

серьёзные нагрузки, это какие ? Какой предел у обычного компа с 4-х ядерный процессором и с 1 Гбит сетевой картой ?
===============================================
(реклама, удалена модератором)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.