Jump to content
Калькуляторы

Еще один HTTP-UDP прокси

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

 

Принцип работы - слушание по умолчанию всех udp-каналов, полученных из командной строки, запись их в небольшой буфер, и отдача клиентам по http с небольшим прекешем (2 секунды). Это позволяет клиенту очень быстро выполнить буферизацию и сразу начать просмотр. Особенно шустрое включение происходит на smart tv. Используется epoll, что позволяет улучшить качество работы, однако из-за этого программа собирается только в linux.

 

Запускается так:

 

./inputtcp -p <порт> -u 239.71.91.1:1234 -u 239.71.91.2:1234 …

 

Программа начинает слушать на заданном http-порту и обслуживает группы 239.71.91.1:1234, 239.71.91.2:1234 и остальные, заданные при запуске. Любые другие группы вызовут ошибку 404. Формат запроса - стандартный - /udp/239.71.91.1-1234, статистику можно получить по запросу /stat - по всем клиентам. Особенно понравилась возможность смотреть количество переполнений буфера у клиентов - поле overruns в таблице.

 

Из ограничений - пока все работает в одном треде, но ничего не мешает запустить несколько экземпляров софтины, исходя из количества ядер, для обслуживания разных групп на разных портах, и сформировать плейлист исходя из этого. Также в файле inputtcp.с можно подправить максимальное количество подключений (стоит сейчас 512).

 

По опыту - работает у нас уже 2 недели, пики в 300 пользователей в момент трансляции закрытия олимпиады и прочих событий пережили нормально. Качество не сравнить с udpxy, в котором уже при 50 клиентах начинались затыки и рассыпания, а HD вообще было невозможно смотреть. Здесь же с этим все идеально. Больше у нас по tcp не смотрят. Будет интересно, если кто-нибудь попробует на большем количестве абонентов.

itcp.tar.gz

Share this post


Link to post
Share on other sites

udpxy давно пора закапывать, там уже помочь не чем :)

У меня пока была однопоточная тянула до 3 гигабит на выход при одном гиге входа, на интеле выше средней приличности.

Share this post


Link to post
Share on other sites

закапывайте обратно. скоро выложу http-стример с zero-copy и дающий 4Гбит/с с одного ядра E5620 при 57% cpu usage(этого ядра) и 40k коннектов.

 

epoll/kqueue + sendfile. работает на фре, линуксе и должно на соляре.

Share this post


Link to post
Share on other sites

4 гигабита и 40К соединений? Это же 100 кбит поток.

Число клиентов тут роли не играет(точнее, оно влияет на число контекстсвитчей, т.к. для большего числа файловых дескрипторов придется звать sendfile).

 

Про вашу нелюбовь к sendfile() я помню, но если файл всегда в кеше - проблем никаких. вот nginx очень интересно работает на побочных эффектах AIO(читая через aio 1 байт, а всё остальное - sendfile).

 

тут нашелся человек с 40G в лабе, так что посмотрим.

Edited by ^rage^

Share this post


Link to post
Share on other sites

Что-то не компилиться на убунуту х64 13.04

 

/itcp# make
gcc -lglib-2.0 -lpthread -g -o inputtcp inputtcp.o socket.o packbuf.o helper.o reqhead.o resphead.o resource.o radix-tree.o
inputtcp.o: In function `http_thread':
/home/user/itcp/inputtcp.c:375: undefined reference to `pthread_detach'
inputtcp.o: In function `main':
/home/user/itcp/inputtcp.c:767: undefined reference to `pthread_create'
collect2: ошибка: выполнение ld завершилось с кодом возврата 1
make: *** [inputtcp] Ошибка 1

Share this post


Link to post
Share on other sites

Первые результаты тестирования показали хорошие результаты, но в статистеке заметил вот такую штуку

225.2.2.129:1234 total packets=18509943 bufpos=1942

х.109.235.134 time=25:31, queue=224 fd=92 in_epoll=0 overruns=166

х.109.235.134 time=182:59, queue=3446 fd=91 in_epoll=0 overruns=1183

х.109.235.134 time=190:9, queue=1397 fd=89 in_epoll=0 overruns=1234

 

Как понимаю не закрываються конекты :( overruns только увеличиваються

Можно ли установить timeout если overruns превысит какого то значения?

Share this post


Link to post
Share on other sites

> pthread_create(&http_thread_t, NULL, http_thread, harg);

 

 

Вы серьезно? На каждого клиента тред?

Share this post


Link to post
Share on other sites

gcc -o inputtcp inputtcp.o socket.o packbuf.o helper.o reqhead.o resphead.o resource.o radix-tree.o -lglib-2.0 -lboost_system -lpthread -g -lrt

 

собрал без -lboost_system

запускается, но все равно не работает. Иногда картинка появиться, но дальше не показывает...

 

=ERROR REPORT==== 25-Mar-2014::13:41:08 ===
** Generic server <0.46.0> terminating
** Last message in was {http,#Port<0.956>,
                          {http_request,'GET',
                              {abs_path,"/udp/239.0.100.1:1234"},
                              {1,0}}}
** When Server state == {state,#Port<0.956>,undefined}
** Reason for termination ==
** {unhandled_path,"/udp/239.0.100.1:1234"}
>> ~n
=ERROR REPORT==== 25-Mar-2014::13:41:08 ===
** Generic server <0.47.0> terminating
** Last message in was {http,#Port<0.957>,
                          {http_request,'GET',
                              {abs_path,"/udp/239.0.100.1:1234"},
                              {1,0}}}
** When Server state == {state,#Port<0.957>,undefined}
** Reason for termination ==
** {unhandled_path,"/udp/239.0.100.1:1234"}

Share this post


Link to post
Share on other sites

запускается, но все равно не работает. Иногда картинка появиться, но дальше не показывает...

 

=ERROR REPORT==== 25-Mar-2014::13:41:08 ===
** Generic server <0.46.0> terminating
** Last message in was {http,#Port<0.956>,
                          {http_request,'GET',
                              {abs_path,"/udp/239.0.100.1:1234"},
                              {1,0}}}
** When Server state == {state,#Port<0.956>,undefined}
** Reason for termination ==
** {unhandled_path,"/udp/239.0.100.1:1234"}
>> ~n
=ERROR REPORT==== 25-Mar-2014::13:41:08 ===
** Generic server <0.47.0> terminating
** Last message in was {http,#Port<0.957>,
                          {http_request,'GET',
                              {abs_path,"/udp/239.0.100.1:1234"},
                              {1,0}}}
** When Server state == {state,#Port<0.957>,undefined}
** Reason for termination ==
** {unhandled_path,"/udp/239.0.100.1:1234"}

 

подскажу немного: у вас работает сервер на эрланге, а не на C

Share this post


Link to post
Share on other sites

запускается, но все равно не работает. Иногда картинка появиться, но дальше не показывает...

 

=ERROR REPORT==== 25-Mar-2014::13:41:08 ===
** Generic server <0.46.0> terminating
** Last message in was {http,#Port<0.956>,
                          {http_request,'GET',
                              {abs_path,"/udp/239.0.100.1:1234"},
                              {1,0}}}
** When Server state == {state,#Port<0.956>,undefined}
** Reason for termination ==
** {unhandled_path,"/udp/239.0.100.1:1234"}
>> ~n
=ERROR REPORT==== 25-Mar-2014::13:41:08 ===
** Generic server <0.47.0> terminating
** Last message in was {http,#Port<0.957>,
                          {http_request,'GET',
                              {abs_path,"/udp/239.0.100.1:1234"},
                              {1,0}}}
** When Server state == {state,#Port<0.957>,undefined}
** Reason for termination ==
** {unhandled_path,"/udp/239.0.100.1:1234"}

 

подскажу немного: у вас работает сервер на эрланге, а не на C

Удалил эрланге, толку нету все равно(

 

./inputtcp -p 8899 -u 239.0.100.1:1234
accepted http connection from 172.16.1.248:59745
Status ok
172.16.1.248:59745 requested: </udp/239.0.100.1:1234>
Preparing sender thread
sender thread for http found
skipping 1 packets

 

и в влц не показывает

Share this post


Link to post
Share on other sites

> pthread_create(&http_thread_t, NULL, http_thread, harg);

 

Вы серьезно? На каждого клиента тред?

 

Тред на http-сессию, для обработки запроса. После этого fd клиента передается в общий пул и тред убивается.

 

skipping 1 packets

 

и в влц не показывает

 

Судя по выделенному, не идет udp-поток. Посмотри несколько раз /stat - увеличивается ли атрибут total packets?

Share this post


Link to post
Share on other sites

 

skipping 1 packets

 

и в влц не показывает

 

Судя по выделенному, не идет udp-поток. Посмотри несколько раз /stat - увеличивается ли атрибут total packets?

 

Неа, не увеличивается total packets, картинка в влц появилась и зависла.

Share this post


Link to post
Share on other sites

закапывайте обратно. скоро выложу http-стример с zero-copy и дающий 4Гбит/с с одного ядра E5620 при 57% cpu usage(этого ядра) и 40k коннектов.

 

epoll/kqueue + sendfile. работает на фре, линуксе и должно на соляре.

 

День добрый ! А когда выложите то? Хочется пощупать ))) Уж больно аппетитно выглядит. ))

Share this post


Link to post
Share on other sites

Тред на http-сессию, для обработки запроса. После этого fd клиента передается в общий пул и тред убивается.

и что, при 8k запросов в секунду будете создавать/убивать 8k тредов в секунду? может, лучше пул тредов?

Share this post


Link to post
Share on other sites

Это же не HLS сервер, а UDP -> HTTP прокси. 8К подключений в секунду — это нерассчетная нагрузка.

 

Вопрос в другом: каждый клиент будет стоить в такой системе порядка 2 мегабайт памяти. Т.е. 4000 клиентов обойдутся чисто в 8 Гб только на стеки тредов.

 

Архитектура с тредом на клиента имеет кучу изъянов и странно её видеть в чем-то, что делается сегодня.

Share this post


Link to post
Share on other sites

Еще раз - треда на клиента нет, есть тред только на время обработки запроса GET. Потом тред убивается и работа идет только с клиентским fd. На 500 клиентах количество занимаемой памяти не изменилось ни на мегабайт.

 

и что, при 8k запросов в секунду будете создавать/убивать 8k тредов в секунду? может, лучше пул тредов?

 

При таких нагрузках уже будут ресурсы допилить либо эту программу, либо купить что-то готовое. Пока же у нас 300-400 клиентов, и не в секунду, а в час пик одновременно смотрящих, под такие запросы и сделал софтину. Бесплатные решения не устраивали, а коммерческие - были неоправданно дорогие.

 

Неа, не увеличивается total packets, картинка в влц появилась и зависла.

Значит 100% не идет мультикаст-поток, или прекращает идти после запуска. Точно не включен fast leave, ограничение количества потоков или еще что-нибудь в этом роде? Программа запрашивает все потоки сразу, и должна получать их даже если никто не смотрит.

Share this post


Link to post
Share on other sites

Вспомнился Courier Mail Server 1.56 и ранее, он тоже создавал по потоку на клиента.

А досить его было легко: нужно было только создать одновременно пачку соединений (порядка 2к под х32) и всё, память кончалась и он высыпался.

Здесь такая же история: цепляемся несколько тыщ коннектов, и не шлём данных или по одному байту можно цедить запрос, и где то кончится память :)

Share this post


Link to post
Share on other sites

Вспомнился Courier Mail Server 1.56 и ранее, он тоже создавал по потоку на клиента.

Третий раз - по потоку на клиента не создается. Тред создается только на время обработки запроса GET, потом убивается и дальше клиент обслуживается главным процессом через epoll. На сотни тысяч одновременных подключений оно и не рассчитано, для этого есть другие решения. Свою задачу предложенное решение выполняет более, чем хорошо.

 

Если у вас во внутренней сети есть проблема c ddos-ерами, то это можно решить парой строчек в iptables. Или доработать софтину, и выложить изменения тут :)

Share this post


Link to post
Share on other sites

Третий раз - по потоку на клиента не создается. Тред создается только на время обработки запроса GET, потом убивается и дальше клиент обслуживается главным процессом через epoll.

Речь о том, что клиент подключается и шлет букву "G". Через минуту - букву "E"... к 30й минуте подходим к CRLF первой строки запроса...

Share this post


Link to post
Share on other sites

Третий раз - по потоку на клиента не создается. Тред создается только на время обработки запроса GET, потом убивается и дальше клиент обслуживается главным процессом через epoll.

Ещё раз перечитайте внимательно предыдущий пост.

По шагам:

1. Подключаемся и не шлём запрос, просто висим, итого: потоки +1

2. Подключаемся ещё раз и не шлём запрос, просто висим, итого: потоки +2

...

Все эти треды будут висеть и ждать гет запрос.

 

Если у вас во внутренней сети есть проблема c ddos-ерами, то это можно решить парой строчек в iptables. Или доработать софтину, и выложить изменения тут :)

Я свою лучше ещё доработаю, начинать с начала как то не интересно :)

Там уже дошло до разгребания MPEG2-TS: она научилась собирать у себя в памяти все нужные PSI таблицы, умеет их обратно выдавать в самом начале потока новому клиенту, чтобы он не дропал до пол секунды потока пока дождётся этих самых таблиц.

Отсюда до HLS рукой подать :)

И заодно EPG (EIT) у меня тоже собирается (тк это часть PSI), научить отдавать через веб в любом формате дело пары вечеров.

zerocopy тоже не проблема, совсем немного менять, дольше вникать в особенности линуха и искать стенд для тестов на 10г или более.

Share this post


Link to post
Share on other sites

1. Подключаемся и не шлём запрос, просто висим, итого: потоки +1

Если такая проблема есть, доработать не сложно - либо в iptables, либо ограничением количества подключений с одного IP в самой софтине. Это явно не тянет на фатальный баг. У нас внутри сети ддосеров не наблюдалось, а в открытый интернет сервер не светим.

 

Я свою лучше ещё доработаю, начинать с начала как то не интересно :)

Я знаю, что у тебя хорошее решение, только для 200-300 пользователей дороговато, особенно с ежегодными платежами.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.