LINUX.ORG.RU

Быстрый многопоточный UDP сервер

 , , , ,


1

2

Нужен фреймверк или библиотека для написания примитивного асинхронного многопоточного сервера для мультикастинга/и не только/ UDP на сях. Скорость req/sec должна быть выше, чем у libuv (нужно 10-12 тысяч req/sec при длине пакета равной hello world на одном ядре digitalocean[kvm], libuv выдаёт 7.000 на одном ядре), vert.x не предлагать, он не плох, но java же. Есть что-нибудь акромя libuv и libevent с libev?
Какая библиотека подойдёт лучше всего, при условии максимальной производительности?

★★★★★

нужно 10-12 тысяч req/sec

Ну с либевент у меня обработка TCP запроса занимала 100-120 микросекунд.

то есть не просто послал и забил, а послал, принял, распарсил, запаковал и отправил ответ. Сервер на i5.

Что, неужно libuv меньше дает?

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

TCP запроса занимала 100-120 микросекунд.

Не так написал. Запрос с клиента занимал в среднем 100-120 микросекунд. Потому как мерилось на стороне клиента.

anonymous
()

Какая библиотека подойдёт лучше всего, при условии максимальной производительности?

libc, делать сразу руками на *poll() без всяких обёрток? Быстрее будет возможно только с допиливанием ядра.

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

Плюсую. *poll() + простой тредпул. Оптимальное количество тредов подберешь сам.

hateyoufeel ★★★★★
()

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

Krieger_Od ★★
()

фреймверк
примитивного
асинхронного
многопоточного
UDP

Тебе точно именно это нужно?

Часто не заморачиваются и UDP вычитывают синхронно (recv/recvfrom) в одной нити, а дальнейшую обработку уже параллелят

Можно читать UDP в несколько нитей. Запустить эти нити и в каждой заблокироваться в recv. Порядок прихода пакетов для каждой нити очевидно будет произвольный

anonymous
()
start() ->
  spawn(fun() -> init() end).

init() ->
  {ok, Skt} = gen_udp:open(3000, [binary]),
  loop(Skt).

loop(Skt) ->
  receive
    {udp, Skt, Rip, Rport, Packet} ->
      gen_udp:send(Skt, Rip, Rport, Packet),
      loop(Skt)
    close ->
      ok
  end.
nanoolinux ★★★★
()

подойдут прямые руки

я лет 10 взад на косом/кривом libevent 1.x получал 25 kreq/sec на четвёртом пне. больше в 100mbit ethernet не пролезало.

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

И не 10к, а отсилы 1к req/sec и то в читерских условиях, реально же, если добавить толику логики сдохнет уже на половине.

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

Erlang тестировал на tcp, хорошо держит только длинные коннекты (keep alive), там же где нужна скорость выдачи req/sec, erlang слабоват. На уровне node.js.

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

Задача раздавать анонсы игровым клиентам по udp. Будет один сервер с виртуальным ядром на digitalocean, cpu прилично ограничено (по сравнению с нативным железом, на котором я и тестирую сейчас), а вот канал широкий. Следовательно, на один этот сервер и пойдут все запросы от игровых клиентов при запуске лаунчера. В принципе, 7.000 запросов в секунду на libuv не плохо, но мне приходится писать тестовый код, перебирая все современные либы, чтобы выбрать лучшую; писать с нуля сокеты на си я, конечно, не хотел - может быть много подводных камней: что лучше принимать и отправлять в одном потоке, чем многопоточно слушать и писать - однозначно будут коллизии в io. Код на libuv довольно простой, с этим проблем нет, а вот, с возможными ошибками по типу создания многопоточного consumer/producer - есть :) у меня опыт только на питоне написания таких вещей, но питон это всё легко дебажить и писать, а тут си.

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

взять erlang или go и не парить людям мозг, взять машину чуть посильнее.

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

На одном ядре digitalocean? Ты сам в это веришь?) на моём хардварном ядре core i7 3770k при 2 Ггц выдаёт около 7-8 тысяч req/sec, вот этот, написанный на C и libuv http сервер:
https://github.com/kellabyte/Haywire
На digitalocean он выдаст ещё меньше, увы...

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

выдаёт около 7-8 тысяч req/sec

Это на физическом интерфейсе? Что-то маловато

У меня на дохлом железе (правда на loopback интерфейсе) синхронный udp эхо-сервер выдает ~30К pps, килобайтные пакеты

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

Щас прибегут железячники и навигачат езернет с юдп на vhdl, который сделает го на порядок. Другой вопрос нахер это надо?

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

не знаю, любая задача предполагает взвешенный и адекватный подход по результатам и затраченному на нее времени, Go в этом плане чемпион, а то что будет с gc в 1.4 и 1.5 версиях сильно улучшит ситуацию в разы.

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

Так на си и гоу одни и те же сокеты. В гоу сокет то же самое, что и си сокет, т.к. гоу компилится в то же, что и си. В гоу просто обвязка над си сокетом. К тому же тут я привел libuv - а это асинхронная обработка сокетов, что само по себе довольно быстро работает, правда, имеет смысл при сложных i/o задачах, коих у меня нет. На гоу я тестил web-framework'и с гитхаба(ревел и ещё какой-то) и они уж точно не быстрее java и си. Примерно на уровне nodejs/erlang. Я вчера уже думал про слинковать статически libuv и гоу код, может, в этом и есть смысл, но всё-равно придется юзать сишный апи libuv...

menangen ★★★★★
() автор топика

Что такое req? Пакет UDP? Ну тогда 10к мелочь, причем для любой сопливой Java, а то и с HTTP. И это значит что у тебя просто худой канал. Ты уверен что 100% CPU жрет?

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

Код мне увидеть можно? Я даже не нашел в слайдах чего это 480кrpspc.

Какбэ это аргументация уровня «на заборе написано», зачем ты её сюда высрал?

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

Ну дак вперёд, ты мне берёшь и показываешь любую гохерню, которая хотябы на хелворде выдаст 480кrpspc. Не можешь - дак зачем ты сюда пришел? Пустословить?

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

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

Всем насрать на твоё время. Почему вы не можете высрать правильное слово «дешевле»? Плохие ассоциации? Ну дак они правильные.

Go в этом плане чемпион

Есть хоть что-то, что это подтверждает? Либо просто пришел, насрал и слинял?

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

выдаёт около 7-8 тысяч req/sec, вот этот, написанный на C и libuv http сервер

Попробуй без всяких левых http-серверов. Убедись только, что загрузка CPU будет 100%, иначе проблемы не в libuv.

#include <uv.h>
#include <stdlib.h>

void alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf)
{
    *buf = uv_buf_init(malloc(size), size);
}

void send_cb(uv_udp_send_t *req, int status)
{
    free(req);
}

void recv_cb(uv_udp_t *handle, ssize_t nread,
    const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags)
{
    free(buf->base);
    if (nread <= 0) return;
    uv_udp_send_t *req = malloc(sizeof(*req));
    uv_buf_t ans = uv_buf_init("Hello world!", 13);
    uv_udp_send(req, handle, &ans, 1, addr, send_cb);
}

int main()
{
    uv_udp_t socket;
    struct sockaddr_in addr;
    uv_udp_init(uv_default_loop(), &socket);
    uv_ip4_addr("0.0.0.0", 6666, &addr);
    uv_udp_bind(&socket, (struct sockaddr *) &addr, 0);
    uv_udp_recv_start(&socket, alloc_cb, recv_cb);
    return uv_run(uv_default_loop(), UV_RUN_DEFAULT);
}

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

это асинхронная обработка сокетов

Зачем?

что само по себе довольно быстро работает

Мифы и легенды.

правда, имеет смысл при сложных i/o задачах, коих у меня нет.

На уровне сокетов это не имеет смысла никогда.

На гоу я тестил web-framework'и с гитхаба(ревел и ещё какой-то) и они уж точно не быстрее java и си.

Это всё в любом случае не имеет смысла сравнивать с си, ибо в любых раскладах сольёт, да и на уровне хелворда это сравнение не жавы/с и не го/с с си, которое само по себе не имеет смысла.

Если ты сравниваешь - сравнивай си/жаба/го-реализации, зачем к этому приплетать ЯП?

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

Нет, тут эрланг знает то полтора человека.

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

Я правильно понимаю, на каждый пакет делается malloc/free? Но зачем? Это какое-то новое веяние?

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

Да, всё верно. В приведённом выше макете это абсолютно необязательно, ведь нам плевать на запрос, но в реальной жизни так приходится делать из-за того, что в коде обработки мы непременно свалимся в какую-нибудь другую асинхронную функцию (работа с файлами, другими сокетами etc.), действие которой по факту в event loop произойдёт позже прихода новой пачки данных. Разумеется, никто не мешает завести свой пул и не дёргать malloc по каждому разу.

mix_mix ★★★★★
()

если есть возможность установи NETMAP

если нет, recvmmsg/sendmmsg и шаруди очереди руками(у нас так 40гбит прилетает)

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