Ресурс Appleinsider.ru запускает новый, не имеющий аналогов в российском интернет-сегменте проект по онлайн-трансляции живых выступлений как молодых музыкальных коллективов, так и именитых музыкантов. Периодичность мероприятия — около 2-х трансляций в месяц.
Первопроходцами 6 декабря стали Федор Чистяков & F4BAND (экс-солист группы НОЛЬ). Во время прямого эфира было около 300 человек, которые смогли оценить чистый студийный звук и атмосферу живого концерта.
Для этой трансляции компания Clodo выделила нам свои мощности и канал шириной 500 мегабит/секунду. Для довольно качественного битрейта потока в 128 килобит/сек это означало 4000 клиентов «в вакууме». Мы предполагали, что придет до 2000 слушателей и перестраховались, однако на этот раз не удалось достичь договоренности с партнерами и наши оценки аудитории оказались сильно заниженными. Попытка привести заинтересованный народ с хабра закончилась баном хабратоварища Dudlik.
Тем не менее, нам довольно успешно удалось провести концерт. Вкратце о технической реализации — мы использовали программу Icecast2 на нескольких серверах, с балансировкой нагрузки с помощью самописного bash-скрипта. Подробнее под катом.
Чтобы воспользоваться возможностями хостинга, нам нужно было создать 5 инстансов, каждому из которых выделялось по 100 мегабит/сек. Общая схема взаимодействия системы выглядела так:

У нас имеется первый сервер, на который транслировался поток-источник (ведущие и музыканты), а тот уже занимался:
1) собственно трансляцией потока для клиентов;
2) ретрансляцией (relay) на другие сервера.
Для раздачи аудиопотока мы использовали Icecast2 из репозитория Ubuntu 10.04. Вкратце, вот список пакетов, которые пришлось установить на сервера трансляции:
Когда поток-источник отсутствует, на первом сервере в эфир идет ротация музыки из определенного каталога. Формируется nonstop-поток с помощью Ices 0.4, который мы собрали из исходников:
Вот наиболее интересные места конфига первого сервера (секции paths, logging, security я опустил), файл /etc/icecast2/icecast.xml:
Конфиг второго и последующих серверов, обращаем особое внимание на секции relay и mount:
Таким образом, при старте icecast2 на втором и следующих серверах они автоматически подключаются к точке монтирования /air первого сервера, копируют его «на лету» и начинают раздавать в своей одноименной точке монтирования /air. На каждый сервер мы ввели ограничение в 600 слушателей, т.е. в идеальном случае канал каждого сервера задействовался бы на 75%.
Теперь о том, как мы равномерно распределяли нагрузку (хотя, как оказалось, это и не потребовалось).
Слушатели могли попасть на онлайн-концерт двумя способами: либо через веб-плеер, открыв страничку podcast.appleinsider.ru и нажав на кнопку Play, либо скопировав ссылку вида air.appleinsider.ru/apple.m3u на той же странице и «скормив» ее своему любимому десктопному/мобильному плееру.
В первом случае балансировка осуществлялась случайно — когда клиент открывал страничку с веб-плеером (кстати, он у нас построен на jPlayer), то с помощью Javascript генерировалось случайное число от 1 до 5, и поток брался с соответствующего сервера (air1-air5).
Во втором случае, т.е. когда пользователь отдавал M3U-ссылку своему плееру, происходило следующее. Вообще, когда у icecast2 запрашивают ссылку вида server/mount.m3u, он сначала ищет файл /usr/share/icecast2/web/mount.m3u, и если находит, отдает его. Нам оставалось лишь правильно формировать этот файлик.
Мы попросту раз в минуту по крону опрашивали нагрузку каждого из серверов, обновляли суммарную статистику и заново перенаправляли символьную ссылку apple.m3u на один из заранее заготовленных файлов, к примеру для первого сервера, этот файл содержал:
Вот собственно bash-скрипт:
Согласен, он немного топоровый, зато рабочий. Если есть предложения по улучшению, с радостью выслушаю.
Вот график объема аудитории во время онлайн-трансляции, 280 человек в пике:

Подписаться на подкаст и скачать запись онлайн-концерта можно тут: RSS | MP3 | iTunes
Следующее мероприятие планируется на 25 декабря. О его участниках пока говорить не будем, т.к. переговоры находятся в самой активной стадии. Все подробности и анонсы можно будет узнать на Appleinsider.ru
Первопроходцами 6 декабря стали Федор Чистяков & F4BAND (экс-солист группы НОЛЬ). Во время прямого эфира было около 300 человек, которые смогли оценить чистый студийный звук и атмосферу живого концерта.
Для этой трансляции компания Clodo выделила нам свои мощности и канал шириной 500 мегабит/секунду. Для довольно качественного битрейта потока в 128 килобит/сек это означало 4000 клиентов «в вакууме». Мы предполагали, что придет до 2000 слушателей и перестраховались, однако на этот раз не удалось достичь договоренности с партнерами и наши оценки аудитории оказались сильно заниженными. Попытка привести заинтересованный народ с хабра закончилась баном хабратоварища Dudlik.
Тем не менее, нам довольно успешно удалось провести концерт. Вкратце о технической реализации — мы использовали программу Icecast2 на нескольких серверах, с балансировкой нагрузки с помощью самописного bash-скрипта. Подробнее под катом.
Техническая реализация
Чтобы воспользоваться возможностями хостинга, нам нужно было создать 5 инстансов, каждому из которых выделялось по 100 мегабит/сек. Общая схема взаимодействия системы выглядела так:

У нас имеется первый сервер, на который транслировался поток-источник (ведущие и музыканты), а тот уже занимался:
1) собственно трансляцией потока для клиентов;
2) ретрансляцией (relay) на другие сервера.
Для раздачи аудиопотока мы использовали Icecast2 из репозитория Ubuntu 10.04. Вкратце, вот список пакетов, которые пришлось установить на сервера трансляции:
g++ libmp3lame-dev libshout3-dev icecast2 libperl-dev libmp3-info-perl
Когда поток-источник отсутствует, на первом сервере в эфир идет ротация музыки из определенного каталога. Формируется nonstop-поток с помощью Ices 0.4, который мы собрали из исходников:
Музыка хранится в каталоге /home/ftp, а ID3-теги из них вытаскивались с помощью Perl-модуля, взятого отсюда (для этого мы собирали ices с ключом --with-perl). Конфиг /usr/local/etc/ices.conf:wget http://downloads.us.xiph.org/releases/ices/ices-0.4.tar.gz tar -zxvf ices-0.4.tar.gz cd ices-0.4 ./configure --with-perl make make install
<?xml version="1.0"?> <ices:Configuration xmlns:ices="http://www.icecast.org/projects/ices"> <Playlist> <Randomize>1</Randomize> <Type>perl</Type> <Module>ices</Module> <Crossfade>5</Crossfade> </Playlist> <Execution> <Background>0</Background> <Verbose>0</Verbose> <BaseDirectory>/tmp</BaseDirectory> </Execution> <Stream> <Server> <Hostname>air1.appleinsider.ru</Hostname> <Port>1976</Port> <Password>SOURCEPASSWORD</Password> <Protocol>http</Protocol> </Server> <Mountpoint>/nonstop</Mountpoint> <Name>AppleInsider.ru Radio</Name> <Genre>not specified</Genre> <Description>Music from our listeners</Description> <URL>http://www.appleinsider.ru/ipodcast/</URL> <Public>1</Public> <Bitrate>128</Bitrate> <Reencode>1</Reencode> <Samplerate>44100</Samplerate> <Channels>2</Channels> </Stream> </ices:Configuration>
Вот наиболее интересные места конфига первого сервера (секции paths, logging, security я опустил), файл /etc/icecast2/icecast.xml:
<icecast> <limits> <clients>1000</clients> <sources>6</sources> <queue-size>524288</queue-size> <client-timeout>30</client-timeout> <header-timeout>15</header-timeout> <source-timeout>10</source-timeout> <burst-on-connect>1</burst-on-connect> <burst-size>65535</burst-size> </limits> <authentication> <source-password>SOURCEPASSWORD</source-password> <relay-password>RELAYPASSWORD</relay-password> <admin-user>admin</admin-user> <admin-password>ADMINPASSWORD</admin-password> </authentication> <hostname>air1.appleinsider.ru</hostname> <listen-socket> <port>1976</port> </listen-socket> <mount> <mount-name>/nonstop</mount-name> <charset>UTF8</charset> </mount> <mount> <mount-name>/air</mount-name> <max-listeners>600</max-listeners> <charset>UTF8</charset> <fallback-mount>/nonstop</fallback-mount> <fallback-override>1</fallback-override> </mount> . . . </icecast>
Конфиг второго и последующих серверов, обращаем особое внимание на секции relay и mount:
<icecast> <limits> <clients>1000</clients> <sources>6</sources> <queue-size>524288</queue-size> <client-timeout>30</client-timeout> <header-timeout>15</header-timeout> <source-timeout>10</source-timeout> <burst-on-connect>1</burst-on-connect> <burst-size>65535</burst-size> </limits> <authentication> <relay-password>RELAYPASSWORD</relay-password> <admin-user>admin</admin-user> <admin-password>ADMINPASSWORD</admin-password> </authentication> <hostname>air2.appleinsider.ru</hostname> <listen-socket> <port>1976</port> </listen-socket> <relay> <server>air1.appleinsider.ru</server> <port>1976</port> <mount>/air</mount> <local-mount>/air</local-mount> <username>relay</username> <password>RELAYPASSWORD</password> <on-demand>0</on-demand> </relay> <mount> <mount-name>/air</mount-name> <max-listeners>600</max-listeners> <charset>UTF8</charset> </mount> . . . </icecast>
Таким образом, при старте icecast2 на втором и следующих серверах они автоматически подключаются к точке монтирования /air первого сервера, копируют его «на лету» и начинают раздавать в своей одноименной точке монтирования /air. На каждый сервер мы ввели ограничение в 600 слушателей, т.е. в идеальном случае канал каждого сервера задействовался бы на 75%.
Распределение нагрузки
Теперь о том, как мы равномерно распределяли нагрузку (хотя, как оказалось, это и не потребовалось).
Слушатели могли попасть на онлайн-концерт двумя способами: либо через веб-плеер, открыв страничку podcast.appleinsider.ru и нажав на кнопку Play, либо скопировав ссылку вида air.appleinsider.ru/apple.m3u на той же странице и «скормив» ее своему любимому десктопному/мобильному плееру.
В первом случае балансировка осуществлялась случайно — когда клиент открывал страничку с веб-плеером (кстати, он у нас построен на jPlayer), то с помощью Javascript генерировалось случайное число от 1 до 5, и поток брался с соответствующего сервера (air1-air5).
Во втором случае, т.е. когда пользователь отдавал M3U-ссылку своему плееру, происходило следующее. Вообще, когда у icecast2 запрашивают ссылку вида server/mount.m3u, он сначала ищет файл /usr/share/icecast2/web/mount.m3u, и если находит, отдает его. Нам оставалось лишь правильно формировать этот файлик.
Мы попросту раз в минуту по крону опрашивали нагрузку каждого из серверов, обновляли суммарную статистику и заново перенаправляли символьную ссылку apple.m3u на один из заранее заготовленных файлов, к примеру для первого сервера, этот файл содержал:
http://air1.appleinsider.ru:1976/air
Вот собственно bash-скрипт:
#!/bin/sh TOTAL=0 IMIN=1 MIN=100 # Собираем нагрузку (т.е. количество слушателей) каждого сервера # Для этого опрашиваем служебную страничку и парсим ее for NUM in `seq 1 5`; do DATA=`curl --silent http://air$NUM.appleinsider.ru:1976/status2.xsl` AIR=`echo $DATA | sed 's/.*\/air//' | cut -d"," -f4` NONSTOP=`echo $DATA | sed 's/.*\/nonstop//' | cut -d"," -f4` if [ "x${AIR}" = "xCurrent Listeners" ]; then AIR=0 fi if [ "x${NONSTOP}" = "xCurrent Listeners" ]; then NONSTOP=0 echo "air$NUM : $AIR" else if [ "x${NONSTOP}" = "x0" ]; then echo "air$NUM : $AIR" else echo "air$NUM : $AIR / $NONSTOP" fi fi # NOW - нагрузка сервера под номером NUM NOW=`expr $AIR + $NONSTOP` # TOTAL - суммарная нагрузка TOTAL=`expr $TOTAL + $NOW` # Определяем номер наименее нагруженного сервера if [ $NOW -lt $MIN ]; then MIN=$NOW IMIN=$NUM fi done echo "-------------------" echo "Total: $TOTAL" # Обновляем статистику на веб-страничке трансляции echo $TOTAL > stat.txt scp stat.txt podcast:/var/www # Обновляем M3U-файл echo air.m3u --\> http://air$IMIN.appleinsider.ru:1976/air ssh air1 ln -sf /usr/share/icecast2/web/air.m3u_$IMIN /usr/share/icecast2/web/air.m3u echo "Server $IMIN is on duty."
Согласен, он немного топоровый, зато рабочий. Если есть предложения по улучшению, с радостью выслушаю.
Итоги
Вот график объема аудитории во время онлайн-трансляции, 280 человек в пике:

Подписаться на подкаст и скачать запись онлайн-концерта можно тут: RSS | MP3 | iTunes
Следующее мероприятие планируется на 25 декабря. О его участниках пока говорить не будем, т.к. переговоры находятся в самой активной стадии. Все подробности и анонсы можно будет узнать на Appleinsider.ru