Онлайн-концерт в облаках

    Ресурс Appleinsider.ru запускает новый, не имеющий аналогов в российском интернет-сегменте проект по онлайн-трансляции живых выступлений как молодых музыкальных коллективов, так и именитых музыкантов. Периодичность мероприятия — около 2-х трансляций в месяц.

    Первопроходцами 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, который мы собрали из исходников:
    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
    
    Музыка хранится в каталоге /home/ftp, а ID3-теги из них вытаскивались с помощью Perl-модуля, взятого отсюда (для этого мы собирали ices с ключом --with-perl). Конфиг /usr/local/etc/ices.conf:
    <?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
    Поделиться публикацией

    Комментарии 12

      +1
      Вы молодцы! Где бы мне подписаться на получение новостей о грядущих концертах?
        0
        В данный момент пока нигде. Мы планируем вывести этот проект в отдельную ветку, и уже начали делать первые шаги в этом направлении. Пока самый простой выход — это периодически заглядывать вот сюда www.appleinsider.ru/yablochnyj-ogryzok 2-х раз в неделю будет достаточно. Анонс вешаем дня за 3-4 до эфира. Ближайший эфир будет или 20 (что вряд-ли) или 25 (наверняка).
        +7
        согласно вашей схеме у вас air1 — single point of failure.
        если он падает — падает все.
          0
          согласен. надо бы мне к следующей трансляции рассмотреть этот вариант
          0
          21 октября Аймобилка делала видео-трансляцию концерта Мумий Тролль «Владивосток 3000» из клуба Arena Moscow.
          Вещали в два потока: 720p и поменьше, для людей со слабым каналом.
          500-600 пользователей смотрело на протяжении всего концерта.
          30% пользователей — низкий поток, остальные — высокий.
          И даже я смотрел трансляцию, пока ехал домой. 3G (beeline) в пределах ТТК хорошо справлялся.
            +1
            Наши планы не останавливаются на единичной трансляции. Мы планируем проводить их 2 раза в месяц. Сейчас ведутся переговоры с другими интересными группами. На мой взгляд — это новый виток концертной деятельности как для музыкантов, так и для поклонников их таланта. Все — бесплатно для конечного пользователя.
              0
              А где смотрели концерт?
              А то поиск не особо помог, а добавления «онлайн» к запросу — вобще выдаёт ужас.
                0
                онлайн-трансляция была прямо на главной странице.
                +1
                В 2008 году вещал «Абсолютную Дрэг-Битву в середине России». Потока с видео было два. ~380 кбпс для основной массы зрителей. 2мбпс для организованных коллективных просмотров толпой (Москва смотрела в клубе через проектор, в нескольких городах выводили себе на плазму, круче всех отжег Благовещенск — парни болели в сауне :)

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

                Обычного потока — в пике до 10000 (десяти тысяч) одновременного онлайна.

                Раздавал фермой из семи серверов, территориально стоящих по всей России от Владивостока до Москвы и Питера. Не потому, что они легли бы от нагрузки, а чтобы приблизить источники сигнала поближе к зрителям (интернеты тогда за пределами МКАД были совсем не те, что нынче). Сколхозил CDN, короче.

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

                — Вещание проводилось с автодрома, от которого до города и цивилизации порядком километров. Никакой там оптики и прочей красоты не было. Но хорошо хоть было нормальное питание, а то во время трансляции в 2007 году «Красное кольцо» было еще не достроено, поэтому свет добывали сами себе, два дня стуча генераторами. Еще и запитали судейскую палатку и судейский же хронометраж (включая светофоры и отсечку на трассе) :)

                В 2006 всё то же самое, только вообще без подготовленной инфраструктуры — на рулежной дорожке действующего аэродрома. Онлайна было маловато — тысячи 2.5 зрителей, зато храню автограф Недзука Садаши, который тюнил «Скайлайн» победителю. Когда был поставлен рекорд России на четверть мили, мужика начали качать, подбрасывая в воздух. Как только опустили на бетон, у него тут же зазвонила мобила и его поздравили из Японии «оу, круто тебя качают». Он спросил, откуда вы знаете и получил ответ «а мы в интернете видели!». Садаши прифигел, увидел нас, сматывающих кабели, через переводчицу спросил, «интернет это вы?» и, пожав руки, долго благодарил, говоря, что: «я какой-то не настоящий японец, я знаю почти всё про турбонаддув, коленвалы и прошивки бортовых компов, но как работает эта ваша ерунда, что меня качают, а видят в Токио и на Хоккайдо, я совершенно не понимаю» :)

                +1
                Вещал с одного сервера для ~700 человек в 128 кб/сек с icecast2 (канал 100 мбит) и ничего не делал (в плане оптимизации) — полет был идеальным, ни одного обрыва.
                Думаю не стоило так замарачиваться, на таких реально низких нагрузках :)
                  0
                  да, ради 280 человек и правда не стоило так все выстраивать, просто изначально расчет был на куда бОльшую аудиторию)
                    0
                    У вас же там было 500 мбит?) Или думали IceCast загнется с одного процесса раздавать? 14 000 не предел (http://www.icecast.org/loadtest1.php)
                    И 500 мбит это около ~3600 слушателей при потоке в 128 кб/сек

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое