Перейти к содержимому
Калькуляторы

Еще один 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

 

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

 

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

Изменено пользователем ^rage^

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Что-то не компилиться на убунуту х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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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 превысит какого то значения?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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"}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

=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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

=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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

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

 

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

 

skipping 1 packets

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

skipping 1 packets

 

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

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

 

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

По шагам:

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

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

...

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

 

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Join the conversation

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

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.