Ресурс 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
