Предыстория:
Есть площадка с видео контентом, где посещаемость около 500 тысяч уников в сутки. Видео у себя не хранили, а любезно заимствовали с сайтов «партнеров». Ну как заимствовали: в реальном времени парсили с сайта ссылки на видеопотоки и вставляли в свой плеер.

В такой схеме было несколько ключевых проблем:
  • Нужно поддерживать работоспособность парсеров в режиме 24/7 для всех сайтов партнеров, а их не один десяток;
  • Видео иногда удаляются;
  • После определённой нагрузки, а иногда спонтанно, некоторые видео начинают требовать ретрансляции.

В определённый момент поняли, что так жить больше нельзя и нужно раздавать видео со своих серверов. По примерной оценке размер видео был 4-5TB и максимальный порт в час пик около 5-7Gbit/s (после запуска цифры оказались примерно такими же).

Кратко о структуре


Главный сервер:
  • Хранит все видео;
  • Отвечает за загрузку видео с сайта партнера;
  • Распределяет видео по раздающим серверам;
  • Считает статистику популярности видео;
  • Отдает плей-листы для плеера;
  • Является балансировщиком для выбора раздающего сервера;

Раздающий сервер:
  • Раздает видео.

Видео — это все качества (240, 360, 480 и 720) одного видео + фото заставки. Все видео конвертируем в mp4 (H.264 видео и AAC аудио), фото заставки в jpeg.

Все сервера имеют две сетевые карты, каждая с портом 1Gbit/s. Внешняя сетевая карта для раздачи, а внутренняя для распределения видео с главного на раздающие сервера.

Главный сервер один, а раздающих может быть любое количество. Раздающие сервера объедены в группы и один сервер может принадлежать только одной группе. Видео может входить только в одну группу. При запросе видео, балансировка идет только между серверами группы, к которой принадлежит запрашиваемое видео.

Бэкенд реализован на yii2.

Загрузка нового видео


На главный сервер прилетает запрос по API с ссылкой на видео, которое нужно скачать. Если видео поддается парсингу, то оно добавляется в стек на скачивание. После скачивания оно попадает в стек для распределения на раздающие сервера. Перед загрузкой на раздающий сервер для видео выбирается группа (выбирается один раз и больше не меняется).

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

После скачивания видео оно конвертируется в mp4 (H.264 видео и AAC аудио) с помощью ffmpeg. Чтобы видео быстро стартовало в плеере его нужно прогнать через MP4Box. Это необходимо из-за того, что ffmpeg помещает “moov-атомы” (мета-информацию о видео) в конец файла, однако, чтобы пользователь имел возможность просматривать видео не дожидаясь его полной загрузки, эти атомы должны быть вначале файла.

Скачивание файлов на главный сервер и их распределение по раздающим серверам работает в несколько потоков. При этом видео скачивается параллельно во всех качествах.

Для многопоточности использую стек для заданий (FIFO) + демон, который поддерживает нужное количество потоков. Поток – это запущенный демоном php через exec. Все добро сделал велосипедом компонентом для yii2. Если будет интересно, то оформлю в рамках отдельной статьи.

Как только, хотябы одно качество, видео загрузится на все раздающие сервера в своей группе оно становится доступным для стриминга.

Хранение видео


Рассмотрим хранения файлов на примере видео с id = 3044:
videoHash – это md5(id)
videoHashChar2 – первые два символа от videoHash
quality – качество видео (240, 360, 480, 720)

storage/image/<b>{videoHashChar2}</b>/<b>{videoHash}</b>.jpg  
storage/video/<b>{videoHashChar2}</b>/<b>{videoHash}</b>.<b>{quality}</b>.mp4  
 
md5(3044) = b8af7d0fbf094517781e0382102d7b27 
storage/image/b8/b8af7d0fbf094517781e0382102d7b27.jpg 
storage/video/b8/b8af7d0fbf094517781e0382102d7b27.240.mp4 
… 
storage/video/b8/b8af7d0fbf094517781e0382102d7b27.720.mp4


Дополнительная иерархия в виде videoHashChar2 нужна, чтобы избежать тормозов с большим количеством файлов в одной директории.

Структура хранения файлов на главном и раздающем сервере одинаковая. Для удобства загрузки файлов на раздающие сервера они смонтированы на главный сервер через nfs по локальной сети.

Защита ссылок


Все ссылки закреплены за пользователем и имеют ограниченный срок жизни. Пример ссылок:
XXX.XXX.XXX.XXX/balancer/play-list/6875?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f 
XXX.XXX.XXX.XXX/balancer/image/6875.jpg?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f 
XXX.XXX.XXX.XXX/balancer/video/6875.480.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f

XXX.XXX.XXX.XXX/balancer/play-list/<b>{videoId}</b>?ue=<b>{expires}</b>&uh=<b>{hash}</b>

Параметры:
videoId – идентификатор видео;
expires – время окончания жизни ссылки;
hash – хеш из параметров ссылки, данных пользователя и соли (videoId, expires, salt, ip, UserAgent, …).

Если проверка проходит успешно, то выбрасываю для nginx заголовок X-Accel-Redirect. Прямой доступ на видео закрыт директивой internal. Первоначально хотел использовать ngx_http_secure_link_module, но для гибкости чтобы не дергуть каждый раз админа перевел проверку на бэкенд.

Главный сервер


Параметры:
  1. Hexa Xeon E5-2430v2, 6х2.50GHz, 4x 8TB SATA3 7.200 RPM, 48GB DDR3 ECC;
  2. CentOS Linux 6;
  3. Raid 10;
  4. Порт 1Gbit/s;
  5. Nginx 1.8 + php-fpm (php 5.6), mysql 5.5.

Конфиг nginx
split_clients "${remote_addr}${request_time}${time_local}" $balance_g1_addr { 
    33% AAA.AAA.AAA.AAA; 
    33% BBB.BBB.BBB.BBB; 
    34% CCC.CCC.CCC.CCC; 
} 
 
split_clients "${remote_addr}${request_time}${time_local}" $balance_g2_addr { 
    33% DDD.DDD.DDD.DDD; 
    33% EEE.EEE.EEE.EEE; 
    34% FFF.FFF.FFF.FFF; 
} 
 
split_clients "${remote_addr}${request_time}${time_local}" $balance_g3_addr { 
    100% GGG.GGG.GGG.GGG;   
} 
 
server { 
    charset utf-8; 
    client_max_body_size 1024M; 
    listen XXX.XXX.XXX.XXX:80; 
    server_name XXX.XXX.XXX.XXX; 
    root        /home/server/site/web; 
    index       index.php; 
    access_log  off; 
    error_log   /var/log/nginx/servers_error.log; 
    
    location / { 
        try_files $uri $uri/ /index.php?$args; 
    } 
    
    location /storage { 
        root /home/server; 
        internal; 
    } 

    location ~ \.php$ { 
        include fastcgi_params; 
        fastcgi_param SCRIPT_FILENAME /home/server/site/web/$fastcgi_script_name; 
        fastcgi_pass unix:/tmp/server1-fpm.sock; 
        try_files $uri =404; 
    } 
    
    location ~ /\.(ht|svn|git) { 
        deny all; 
    } 
     
    location ~ /ds-g1/(.+)$ { 
        internal; 
        return 302 "http://$balance_g1_addr/$1?$args"; 
    } 
 
    location ~ /ds-g2/(.+)$ { 
        internal; 
        return 302 "http://$balance_g2_addr/$1?$args"; 
    } 
 
    location ~ /ds-g3/(.+)$ { 
        internal; 
        return 302 "http://$balance_g3_addr/1?$args"; 
    } 

} 


Баланcировка между раздающими серверами в рамках группы реализована через модуль ngx_http_split_clients_module. Когда запрашивается видео, то на бэкенде определяет к какой группе принадлежит видео и выбрасывает заголовок X-Accel-Redirect.

Пример:
XXX.XXX.XXX.XXX/balancer/video/7190.720.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f


Если видео с id=7190 принадлежит к группе 2, то заголовок X-Accel-Redirect будет следующим:
/ds-g2/sv/7190.720.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f
. Потом будет выбран сервер из группы 2 (например EEE.EEE.EEE.EEE) и отправлен редирект 302 Moved Temporarily на
EEE.EEE.EEE.EEE/sv/7190.720.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f
.

В нашей конфигурации 3-и группы. Так как все раздающие сервера размером 2TB и портом 1Gbit/s, то с учетом разбивки имеем 6TB полезного места и суммарный порт 7GB. 1 и 2 группа — это суммарный объем 4TB и порт 6Gbit/s. 3 группа – это объем 2TB и порт 1Gbit/s.

3 группа особенная, в ней находятся самые непопулярные видео. Данная группа заполняется в полуавтоматическом режиме. Новые ролики распределяются только по первым двум группам, так как они потенциально являются популярными (по крайней мере первое время). Это сделано, чтобы по максимуму использовать место и порт.

Если не делать отдельную группу под непопулярные видео, то в других группах быстро закончится свободное место и при этом канал будет загружен не на 100%.

В группе может быть любое количество серверов. Полезный объем и максимальный размер порта определяется по самому слабому серверу в группе. Группы могут быть с разным объемом и портом.

Такой маленький объем раздающих серверов в 2TB связан с использованием 4x512GB SSD TLC. Эксперимент с 2x4TB SATA3 7,200 RPM закончился фиаско, так как на них смогли выжать только 0.3Gbit/s, при доступном порте 1Gbit/s.

Раздающий сервер


Параметры:
  1. Hexa Xeon E5-2430v2, 6х2.50GHz, 4 x 512GB SSD TLC, 48GB DDR3 ECC;
  2. CentOS Linux 6;
  3. Raid 0;
  4. Порт 1Gbit/s;
  5. Nginx 1.8 + php-fpm (php 5.6).

Конфиг nginx
server { 
    listen       80; 
    root   /home/user/site/web; 
    index  index.php; 
    location ~ \.php$ { 
        include fastcgi_params; 
        fastcgi_param SCRIPT_FILENAME /home/user/site/web$fastcgi_script_name; 
        fastcgi_pass unix:/tmp/upstream1-fpm.sock; 
    } 

    #image 
    location ~ ^/si/.+\.jpg$ { 
        rewrite .* /image.php?$args; 
    } 

    #video 
    location ~ ^/sv/.+\.(\d+)\.mp4$ { 
        rewrite .* /video.php?$args; 
    }

    location ~ ^/image/.+\.jpg$ {  
        root /home/user/storage; 
        internal; 
    }

    location ~ ^/video/.+\.mp4$ {  
        root /home/user/storage; 
        internal; 
        location ~ \.240\.mp4$ { 
            mp4; 
            mp4_buffer_size 1m; 
            mp4_max_buffer_size 10m; 
            sendfile on; 
            tcp_nopush on; 
            tcp_nodelay on; 
            expires max; 
            directio 10m; 
            limit_rate 96k; 
            limit_rate_after 3m; 
        } 

        location ~ \.360\.mp4$ { 
            mp4; 
            mp4_buffer_size     4m; 
            mp4_max_buffer_size 10m; 
            sendfile on; 
            tcp_nopush on; 
            tcp_nodelay on; 
            expires max; 
            directio 10m; 
            limit_rate 256k; 
            limit_rate_after 10m; 
        }   

        location ~ \.480\.mp4$ { 
            mp4;             
            mp4_buffer_size     8m; 
            mp4_max_buffer_size 20m; 
            limit_rate 512k; 
            sendfile on; 
            tcp_nopush on; 
            tcp_nodelay on; 
            expires max; 
            directio 10m; 
            limit_rate_after 10m; 
        }   
   
        location ~ \.720\.mp4$ { 
            mp4; 
            mp4_buffer_size     20m; 
            mp4_max_buffer_size 40m; 
            sendfile on; 
            tcp_nopush on; 
            tcp_nodelay on; 
            expires max; 
            directio 10m; 
            limit_rate 1024m; 
            limit_rate_after 10m; 
        } 
    } 
} 


Раздача видео реализована через модуль ngx_http_mp4_module для псевдо-стриминга. Чтобы его включить достаточно добавить директиву mp4.

Для каждого качества видео задана своя скорость отдачи limit_rate и размер первоночального куска, который будет отдаваться на максимальной скорости limit_rate_after. По коммерческой подписке nginx доступны mp4_limit_rate и mp4_limit_rate_after, которые задаются в секундах (это удобнее в разы, но бюджет на это не предусмотрен).

mp4_buffer_size — начальный размер буфера, используемого при обработке mp4-файлов.
mp4_max_buffer_size — в ходе обработки метаданных может понадобиться буфер большего размера. Его размер не может превышать указанного, иначе nginx вернёт серверную ошибку 500 (Internal Server Error).
sendfile, tcp_nopush, tcp_nodelay – одним словом ускоряет отдачу файлов.
directio – задание минимальный размер файла для включения режима чтение без обращение в кеш операционной системы.
expires – включение клиентское кеширование.

Пример плей-листа


XXX.XXX.XXX.XXX/balancer/play-list/7190?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f


Плей-лист возвращается в формате json:
{ 
  "status": 1, 
  "data": { 
    "listVideo": { 
      "240": "http://XXX.XXX.XXX.XXX/balancer/video/7190.240.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f", 
      "360": "http://XXX.XXX.XXX.XXX/balancer/video/7190.360.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f", 
      "480": "http://XXX.XXX.XXX.XXX/balancer/video/7190.480.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f", 
      "720": "http://XXX.XXX.XXX.XXX/balancer/video/7190.720.mp4?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f" 
    }, 
    "img": "http://XXX.XXX.XXX.XXX/balancer/image/7190.jpg?ue=1440614576&uh=0cbd48e20dc2bf396a2eece00cd9ec2f" 
  } 
} 

Ссылки


Cтриминг видео в «Одноклассниках» — www.highload.ru/2014/abstracts/1636.html
Видеохостинг своими руками — habrahabr.ru/post/111249
ffmpeg — www.ffmpeg.org
MP4Box — gpac.sourceforge.net
ngx_http_mp4_module — nginx.org/ru/docs/http/ngx_http_mp4_module.html
ngx_http_split_clients_module — nginx.org/ru/docs/http/ngx_http_split_clients_module.html
Отдача файлов с помощью nginx — ruhighload.com/index.php/2009/10/31/nginx-dlya-otdaci-failov

Комментарии (108)


  1. ibKpoxa
    01.09.2015 16:24

    А почему такой странный ключик для сплита?

    split_clients "${remote_addr}${request_time}${time_local}"

    Как мне кажется что тут большие шансы что при повторном просмотре видео клиента отправит на другой сервер, вместо ответа «Файл не изменен», т.к. время запроса будет другое.


    1. prodex
      01.09.2015 20:37

      Это не критично


  1. FreeLSD
    01.09.2015 16:48

    А где нашли такие широкие каналы?


    1. esc
      01.09.2015 17:23
      +1

      А сейчас разве не любой крупный ДЦ в прайсах содержит 10G порты с каналом?


      1. FreeLSD
        01.09.2015 17:47

        Интересна цена вопроса и можно ли ввязываться в межоператорские разборки на таких объемах отдаваемого трафика.


        1. esc
          01.09.2015 18:05

          7 Gbit это такая мелочь, что в разборки вы точно не втянетесь. В моем случае, операраторы начали шевелиться, когда трафик перевалил за 150 внутри Украины.

          А цена вопроса разная может быть. 7Гбит скорее всего будет по прайсу. С текущими скачками курсов скложно сказать сколько будет, сильно зависит от размещения и направления трафика.

          От 100Г внутри страны, думаю, можно и бесплатное размещение обсуждать. Хотя, смотря какие перспективы, может и с 50 уже можно;)


          1. prodex
            01.09.2015 19:46

            Специально искали сервера с гарантированным и безлимитным портом 1Gbits/s, а не шаред. Поэтому цена фиксированная за месяц.


            1. esc
              02.09.2015 12:00

              Я говорю о реально больших объемах, когда под вас могут и оборудование закупить специально. Понятно, что не shared.


              1. prodex
                02.09.2015 13:10

                Если так, то да. Но пока объемы не большие)


          1. DjOnline
            01.09.2015 19:51
            +2

            Внутри какой страны?


            1. esc
              02.09.2015 11:59

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


              1. DjOnline
                19.09.2015 13:01

                Я помню такое было 15 лет назад, когда Masterhost платил за трафик для крупногенерящих проектов.
                Сейчас разве кто-то так делает? Предлагает бесплатное размещение то есть бесплатные стойки + канал? Есть пример тех, кто это использует, в России?


      1. prodex
        01.09.2015 19:44

        Этот вариант просчитывали, но он экономически не рентабельный + маштабировать сложнее. Когда нам нужно 7Gbit/s, то зачем платить за 10Gbit/s? А если потребуется 12Gbit/s, то брать два по 10Gbit/s тоже не вариант.


        1. erlyvideo
          01.09.2015 19:48

          есть хостеры, готовые очень вменяемо расширять полосу внутри 10-гигабитного порта.


          1. prodex
            01.09.2015 20:39

            Как понять расширить? Вы рассматриваете вариант, когда сервер с шаред портом, а не с гарантированным?


            1. erlyvideo
              01.09.2015 20:56

              Да вы всё упираетесь в понятия шаред, гарантированный, хотя это условности.

              У хостера есть какой-то объём связности, т.е. его собственный аплинк. Сколько он из этого аплинка вам готов зарезервировать, столько вы и получите. Какая при этом скорость подключения вашего сервера к свитчу — это уже отдельное дело, но удобно иметь 10-гигабитное подключение, при котором хостер берет не за все 10 гигабит, а за меньшую сумму.


              1. prodex
                01.09.2015 21:06

                Я вас понял, но такой сценарий мало вероятен. У них есть сервера с шаред портом 10Gbit/s из которых 1-3Gbit/s будут гарантированными. Но это тоже все по фиксированному прайсу, где свой размер гарантированного порта не протолкнуть.


                1. erlyvideo
                  01.09.2015 22:11

                  это просто такие условия у того хостера где вы находитесь.

                  Мы обычно наших клиентов размещаем в других местах.


                  1. webcasper
                    02.09.2015 08:25
                    +1

                    А в каких местах Вы размещаете своих клиентов?


                  1. kevit
                    08.09.2015 17:22

                    да, тоже интересно)


        1. esc
          02.09.2015 12:02

          Очень просто, 10G при небольшом к-ве серверов будет существенно дешевле, чем ферма гигабитных. Просто за счет стоимости самого железа. Надо только поискать ДЦ, которые делают спец. позиции в прайсах для трафикогенераторов.


          1. prodex
            02.09.2015 13:16

            К сожалению нет. Сервер с 10Gbit и SSD (на мой объем видео) не будет существенно дешевле. Да и не нужно забывать про отказоустойчивость.
            ИМХО 10 серверов по 1Gbit мне кажется надежнее, чем один с портом 10Gbit.

            Конечно я могу ошибать, но если вы знаете где есть такие сервера недорого, то дайте ссылку. Я буду очень признателен.


            1. esc
              02.09.2015 13:25

              Кажется надежнее, на самом деле 10 серверов это менее надежно, чем 2-3. Ссылку на fdcservers я ниже уже бросал, в принципе подойдет любой крупный хостер, у которого в прайсах есть 10Г порты. Надо только ему написать, а не выбирать из стандартных вариантов (те как раз не всегда оптимальны).


            1. kevit
              08.09.2015 17:22

              а сколько по-вашему недорого за честных 10гбит интернета/россии?


              1. esc
                15.09.2015 19:17

                Больше 500 баксов в месяц я думаю рассматривать нет смысла. Тем более, если трафик не на рунет в основном (тогда за эти деньги уже с сервером можно взять).


                1. kevit
                  16.09.2015 07:38

                  микс из когента с харрикейном у fdcservers)) с ценой 0.05 доллара за мегабит:))) но самая большая проблема даже не в этом, а в том что часть ваших пользователей будет постоянно сидеть в congested на россию


                1. kevit
                  16.09.2015 07:41

                  там ниже писали оценку, в 0.6 за мегабит на объеме я еще могу поверить, 0.05 вы примерно можете представить во сколько раз больше продает хостер к своей емкости портов


                  1. esc
                    17.09.2015 02:40

                    Российские хостеры в основном не верят в то, что цены на порты и трафик давно снизились. Потому, даже с учетом кризиса, многие продолжают сидеть в Европе и/или договариваться с точками обмена.


                1. erlyvideo
                  17.09.2015 13:55

                  500 баксов в месяц за 10 гигабит?


                  1. esc
                    18.09.2015 00:06

                    500 баксов в месяц за 10 гигабит.


                    1. erlyvideo
                      19.09.2015 15:13

                      это кто по таким ценам и что именно предлагает?


    1. erlyvideo
      01.09.2015 18:19

      да немало таких предложений.


      1. FreeLSD
        01.09.2015 18:23

        Предложение-то немало, мне интересно по какой цене покупают такие каналы.
        Честные 7 гигабит меньше 350.000 не должны стоить. Вот и интересно кто где почем берет


        1. erlyvideo
          01.09.2015 19:36

          ох, больную тему вы затронули.

          Ваша цена (по сегодняшнему курсу евро) — это хорошее, приличное и качественное предложение. На канале, который можно купить за такие деньги видео обычно не лагает и всё работает.

          Однако есть хостеры, которые не моргнув глазом предлагают чуть ли не за 50 тыс рублей десятку в месяц. Очень тяжело объяснить клиентам таких хостеров, что им продали порт, а не канал до куда-то.


          1. FreeLSD
            01.09.2015 20:13

            Не у одних вас эта тема больная.


            1. CMHungry
              01.09.2015 21:45

              можно ко мне в личку пообщаться, если очень надо


            1. kevit
              08.09.2015 17:23

              и ко мне)


        1. ULP
          01.09.2015 20:28

          да, 350тыр это стоит. если это чистая генерация, то в Билайне, Мегафоне, РТКОмме или прочих операторах ШПД можно вероятно сделать тысяч за 70 если коэффициент будет 1/20 и более.


          1. CMHungry
            01.09.2015 21:46

            не факт. у ШПД с отдачей и так все очень плотно. Скорее просто у магистрала можно обсудить цену на соотношение.


        1. CMHungry
          01.09.2015 21:45

          где, в Москве, в Питере, в Хабаровске? Связность зарубежная, отечественная, запад или китай и иже с ним?


          1. esc
            02.09.2015 12:14

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


        1. BasilioCat
          02.09.2015 14:12

          Если вы, скажем, берете 150 гигабит, договорившись на некоторую цену, а потом вдруг передумали и хотите взять 50. Так вам за 50 предложат заплатить столько же, что и за 150. Ну а 7 — это в розницу, тут примерно ценник понятен
          При больших объемах лучше договариваться о каналах до точек обмена трафиком, и непосредственно о стыках с магистралами и крупными провайдерами, отдавая во внешний канал только то, что нельзя спихнуть остальным


  1. xeioex
    01.09.2015 17:30
    +5

    > sendfile, tcp_nopush, tcp_nodelay – одним словом ускоряет отдачу файлов.
    > directio – задание минимальный размер файла для включения режима чтение без обращение в кеш операционной системы.

    А вы уверены что ваша конфигурация работает так как вы ожидаете?

    читаем документацию и видим:
    Enables the use of the O_DIRECT flag (FreeBSD, Linux),…
    The directive automatically disables (0.7.15) the use of sendfile for a given request. It can be useful for serving large files:

    directio 4m;
    or when using aio on Linux.

    Для кросспроверки читаем маны:
    man 2 open
    O_DIRECT (Since Linux 2.4.10)
    Try to minimize cache effects of the I/O to and from this file. In general this will degrade performance, but it is
    useful in special situations, such as when applications do their own caching.

    Для раздачи файлов и особенно больших nginx полагается на кеш операционной системы, так как она в любом случае кеширует файлы в памяти. В противном случае кеширование будет выполнено в двух местах что не оптимально. Т.е. вы мало того что указываете конфликтующие параметры, так в случае с directio деградируете производительность.

    > одним словом ускоряет отдачу файлов.
    слишком упрощенный взгляд на вещи (особенно если производительность для вас в приоритете), я бы рекомендовал читать документацию внимательно (благо она лаконичная) и не копировать конфигурации не вникая.


    1. prodex
      01.09.2015 21:49

      С кешем операционной системы вышла заминка. Тогда странно, почему nginx рекомендует использовать directio для больших файлов (nginx: directio).


      1. erlyvideo
        01.09.2015 22:13

        до 10 гигабит это всё уже не особо актуально. От directio в том виде, в котором оно есть в линуксе больше проблем, чем решений.

        В других юниксах типа фрибсд тоже не сильно легче.


      1. xeioex
        01.09.2015 22:35

        Изначальная задача directio в том что бы большие, но редкие файлы не вымывали небольшие и часто запрашиваемые файлы из кеша операционной системы.

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


        1. erlyvideo
          01.09.2015 23:25

          Может всё таки скорее для того, что бы софт сам мог управлять кешем?

          Т.е. не большие vs маленькие, а просто перенос знания о полезности кеша в софт? Это же вроде оракл коммитил в линукс.


          1. xeioex
            01.09.2015 23:32
            +1

            Да, это ровно то что указано в мане "...but it is useful in special situations, such as when applications do their own caching", но я говорил про директиву nginx'а directio, а не флаг O_DIRECT.


      1. sebres
        02.09.2015 11:06
        +1

        Вам xeioex практически все верно написал… по крайней мере исходя из вашего сценария.
        При работе с такими большими объемами (гарантированно не помещающимися в кэш) directio только увеличит нагрузку на дисковую систему, т.к. в таком случае имеем множественные блокировки (посредством дискового IO), поэтому лучше вообще использовать поток пулов. Подробнее отличная статья на хабре от VBart.


        1. prodex
          02.09.2015 12:19

          Директиву directio профиксил, но эффект на 1 гигабитном серваке не сильно заметен, наверное для 10 гигабитного разница была бы значительной.
          С потоком пулов давольно интересно, протестирую на одной группе.


          1. xeioex
            02.09.2015 13:45

            А как вы замеряли эффект?


            1. prodex
              02.09.2015 13:50

              Количество подключений, забитость канала и нагрузка на шину диска практически не изменилась.


          1. AterCattus
            02.09.2015 14:49
            +1

            Кстати, aio threads пробовали, понравилось.


  1. esc
    01.09.2015 17:34
    +1

    Хм, вы держите ферму серверов ради 7 Гбит? Еще и 48 ГБ памяти… Откройте для себя 10Г сетевые и правильно настройке aio+directio, как минимум, будете одного с такого сервера десятку раздавать, а не пару гигабит.

    На таких объемах неплохо себя покажут гибридные сервера, где допустим будет пара 4ТБ винтов и 4 ssd + двухпортовая 10Г карта. 2 таких сервера вам запросто 40Г увалят, если каналы будут (и запросов достаточно). (2 скорее для отказоустойчивости)

    Скриптами популярные файлы просто на ssd копируйте с винтов и отдаете всегда с ssd, если они там есть.


    1. prodex
      01.09.2015 19:41

      Серверы с гарантированным портом 1Gbit/s обходятся около 200$. Находятся в Англии.

      >Еще и 48 ГБ памяти…
      С меньшим объемом не было, иначе бы взяли.

      >Откройте для себя 10Г сетевые
      Этот вариант просчитывали, но он экономически не рентабельный + маштабировать сложнее. Когда нам нужно 7Gbit/s, то зачем платить за 10Gbit/s? А если потребуется 12Gbit/s, то брать два по 10Gbit/s тоже не вариант.

      В данной схеме выход 1-2 серверов из строя не обрушит всю систему, просто видео будет отдаваться медленее, но будет работать.


      1. esc
        02.09.2015 12:08

        Ну я понял, что у вас просто не самое подходящее предложение от хостера. Тем не менее, стоит поискать в Европе предложения специально для трафикогенераторов. fdcservers.net мне регулярно спамит какими-то «эксклюзивными» конфигурациями для серверов с 1-2 10Г портами. Хотя на сайте у них хлам какой-то, но полагаю что предложениями с сайта их возможности совсем не ограничиваются. Ну или лизвеб какой-то.

        Канал там честный, нужно только аккуратно к конфигурации железа относиться, они любят впарить старый хлам тем, кто не обращает внимание на платформу.


        1. prodex
          02.09.2015 12:25

          У fdcservers.net ценник c учетом SSD получается значительно выше.


          1. esc
            02.09.2015 12:31

            У них сотни предложений по серверам. В сайте практически ничего нет. За 5 минут выкопал в почте такое:

            2U Dell FS12-TY Dual Xeon L5520--12bay
            64GB RAM
            12 x 2TB or 12 x 120Gb SSD
            10Gbps unmetered $699/mon

            Но думаю, что если с ними списаться, то получится за подобные деньги взять более свежие Ксеоны, которые и 20 прокачают.


    1. NickyX3
      04.09.2015 15:05

      Скриптами популярные файлы просто на ssd копируйте с винтов и отдаете всегда с ssd, если они там есть.

      При таком объеме памяти скриптами можно копировать особо популярные вообще в память применив к примеру tmpfs


      1. esc
        04.09.2015 15:14

        Ну ssd 2ТБ, а памяти всего 48Г. Хотя, можно конечно и туда копировать. У нас суперкеши, которые по 80Г раздают, так и работают. 256ГБ памяти выделено под самый горячий кэш и на него под 40Г и приходится.


        1. NickyX3
          04.09.2015 15:21

          256ГБ памяти выделено

          Да у автора мне кажется объемы поменьше. Когда я работал над (закрытом три года назад) другим проектом мы сливали до десятка роликов в tmpfs (которые просто чекались там через try) объемом 1 гиг всего. На сервер с 8 гигами памяти


  1. nwalker
    01.09.2015 17:59

    > Псевдостриминг
    > 7 Gbit

    Интересная идея, я бы даже сказал, мощная.


  1. BasilioCat
    01.09.2015 18:10
    +2

    На нормальных (но не топовых) SSD вполне реально отдавать 40 гбит с одного сервера. Мешать жесткие диски и SSD на одном сервере мне думается нет смысла — корзин не хватит.

    Мне не понятно только, зачем нужен псевдостримминг, который был придуман только как костыль для флэша, который блокирует заголовки Byte-range. Сейчас любой телефон умеет HTML5 video — можно просто отдавать видео как файлы. Если хочется странного, то в дополнение можно отдавать видео в HLS/HDS, на лету это умеет делать Nginx+, Wowza, FMS, Erlyvideo/Flussonic


    1. prodex
      01.09.2015 20:27

      >На нормальных (но не топовых) SSD вполне реально отдавать 40 гбит с одного сервера
      Отдать можно, но гарантированный и безлимитный порт в 10Gbit/s уже не рентабелен.

      >Сейчас любой телефон умеет HTML5 video — можно просто отдавать видео как файлы.
      Тогда не будет возможности перемотки (без полного скачивания ролика).

      На счет HLS думал, но конвертация налету кажется плохой затеей. Нужно протестировать нагрузку. А хранить одновременно mp4 и HLS накладно. Да и мобильного трафика не так много, как хотелось бы.


      1. BasilioCat
        01.09.2015 20:52

        40 Гбит — ну вопрос в объемах… 10Гб порты уже есть даже для арендованных серверов в Московских ДЦ, ну а цена — вопрос рентабельности проекта. Обычно 10 шт портов по 1Гбит стоят дороже. У одного видеохостинга была года полтора назад полоса в 180 гбит/с, ну и одноклассники тут озвучивали свои объемы трафика.

        HTML5 video с файлом обработанным mp4box перематывается нормально и без скачивания контента — проверьте с телефона сниффером на сервере

        HLS включает в себя смену контейнера на mpeg ts — по опыту моего коллеги, написавшего модуль для nginx, это не сильно накладная операция. Но практически все устройства, умеющие HLS, умеют и HTML5 video, так что особой необходимости для vod нет, только для live-потоков — для них нет альтернативы.


        1. erlyvideo
          01.09.2015 21:00

          тем не менее смена HLS на mp4 на хостинге повышает расход трафика на от 30% до 100%

          Это присходит по разным причинам: от промежуточных проксей до глюкавых реализаций плееров.


          1. BasilioCat
            01.09.2015 21:06

            Прокси — это да. В целом HLS/HDS для них в первую очередь и придуман. А какие клиенты кривые — да еще чтоб давать такой процент?


            1. BasilioCat
              01.09.2015 21:09
              +1

              Собственно, псевдостримминг тоже не совсем решение для проксей — плеер обычно спрашивает не кусками, а от нужной позиции (а то и с начала) и до конца файла, что точно также дает выкачивание файла проксей. А то и по нескольку раз с разными параметрами начала просмотра =(


              1. erlyvideo
                01.09.2015 22:14

                Конечно. Клиент поскипал несколько раз субтитры с запросом ?from= а прокси сервер докачал один файл 8 раз.


          1. prodex
            02.09.2015 13:33

            А есть у вас статистика mp4 против DASH по разнице в трафике?


            1. erlyvideo
              02.09.2015 13:49

              нууу DASH у нас вообще пока крайне редок =)


              1. prodex
                02.09.2015 13:51

                А HLS получается экономит 30-100% канала, верно?


                1. erlyvideo
                  02.09.2015 14:28

                  По сравнению с просто раздачей mp4 — да. Такие цифры дают нам наши клиенты.


        1. prodex
          01.09.2015 21:31
          +1

          >Сейчас любой телефон умеет HTML5 video — можно просто отдавать видео как файлы.
          Тогда не будет возможности перемотки (без полного скачивания ролика).
          HTML5 video с файлом обработанным mp4box перематывается нормально и без скачивания контента — проверьте с телефона сниффером на сервере

          Мобильного трафика меньше половины. А по десктопным браузерам встречаются еще те мамонты. Поэтому использовать на всех клиентах HTML5 Video пока не получится.


          1. BasilioCat
            01.09.2015 21:48

            Снимите статистику по юзерагентам из логов — вы удивитесь сколько из них поддерживают HTML5 video / h264. Fallback на флэш для ie6 можно реализовать отдельно — благо файлы одни и те же для псевдостимминга и html5 video


            1. prodex
              02.09.2015 06:36

              Где есть возможность, я уже использую тег HTML5 Video


      1. erlyvideo
        01.09.2015 20:59

        да не, конвертация на лету это не страшно =) Наш Flussonic без проблем 9-10 гигабит отдает с генерацией HLS/HDS на лету из mp4.


        1. esc
          02.09.2015 12:03
          +1

          А nginx делает 70 на аналогичной задаче;)


          1. erlyvideo
            02.09.2015 12:51

            Когда ещё авторизацию и ведение сессий к этому научится, будет вообще неплохо =)


          1. ArjLover
            11.09.2015 11:31

            Речь про nginx+ или фришный тоже умеет это делать?


    1. TheRaven
      02.09.2015 10:11
      +1

      Для отдачи mp4 в виде HLS\HDS\DASH еще можно вот такую штуку использовать — github.com/kaltura/nginx-vod-module


      1. BasilioCat
        02.09.2015 13:46

        На первый взгляд весьма интересное решение, да еще и Open Source. Спасибо, очень ценная рекомендация!


    1. esc
      02.09.2015 12:37

      Псевдостриминг нужен для флеша. А флеш на данный момент безальтернативный проигрыватель видео с высоким разрешением и в высоком битрейте. Мы уже 2 года пытаемся отказаться от флеша, но приходится оставлять legacy версию т.к. html5 банально жрет больше ресурсов и видео тормозит на слабых компьютерах (которых немало). И это не проблема корявой реализации плеера, у ютуба история аналогичная.

      Да, на i7 и наверное даже i3 разница неощутима, но в мире пока не у всех i7.


      1. BasilioCat
        02.09.2015 13:15

        Flash содержит в себе вполне обычный декодер для h264, как и браузер для HTML5 video. Насколько я знаю, флэш умеет пропускать кадры, если процессор не справляется, и умеет ускорять декодирование на GPU и/или SSE3. Не тестировал декодеры браузеров, но мне смутно кажется, что они с этим должны справляться не хуже. Вы тестировали производительность декодирования одного и того же файла во флеше и средствами браузера?

        Ну и флэш давным давно умеет HDS (это нативный для него формат), и не так давно HLS при помощи сторонних плагинов для проигрывателей (довольно кривая реализация на мой взгляд), что делает псевдостримминг слегка устаревшим


        1. esc
          02.09.2015 13:22
          +2

          У флеша проигрыватель просто более оптимизирован, особенно полноэкранный. Наверное, потому что там реально полноэкранный режим, а не просто распахнутое на весь экран окно, как в случае html5. Хотя, возможно не только в этом дело. Факт — флеш на слабых машинах показывает себя гораздо лучше в данной задаче. Я это разумеется тестировал, более того, legacy плеер именно этой задаче и занимается — показывает те же файлы, что и html5, но более оптимально.

          Касательно hds/hls, да, флеш это умеет. А html5 на десктопах — практически нет;)

          mp4 + псевдостриминг это самый простой вариант. Не надо медиасерверов, не надо определять что там кто умеет принимать и т.д. Бесплатный штатный модуль к nginx и ваше видео доступно всегда и везде.

          Да, стриминг поддерживает кое-какие фичи и позволяет сэкономить какой-то трафик в определнных случаях. Но сложность и стоимость внедрения сильно выше и часто это банально того не стоит.


  1. Antex
    01.09.2015 18:27
    +3

    ffmpeg может сам ставить moov в начало: -movflags faststart (правда, я не помню с какой это версии)

    Как насечет перейти на hls/mpeg-dash? Например, nimble умеет хорошо «трансмуксить» налету из mp4 в hls и прочее.


    1. BasilioCat
      01.09.2015 21:00

      Если я не путаю, то ffmpeg это делает вторым проходом, пересоздавая файл, что в целом от mp4box и qt-faststart не отличается.

      HLS десктопом не поддерживается (кроме Safari по-моему), перепаковывать на лету умеет куча платного софта примерно в одной ценовой категории (до1000$ за серверную лицензию) — я писал чуть выше список


      1. w7062c
        02.09.2015 05:51
        +1

        На десктопе оно хорошо поддерживается сторонними плеерами — навскидку это JWPlayer и bitdash. Кроме того, можно на лету генерить MPEG-DASH, у которого нативная поддержка активно появляется на разных платформах, вплоть до телевизоров. Ну а по цене — Нимбл, например, бесплатен.


        1. NickyX3
          04.09.2015 15:17

          Еще Clappr умеет


      1. Antex
        02.09.2015 13:30
        +2

        на десктопы и тв можно загонять видео в dash, а на мобилы в hls. Nimble все это умеет и он бесплатен.


  1. kolipass
    01.09.2015 19:27
    +1

    Не совсем по теме статьи, но меня волнует: а какой mp4 Profile реализован?


    1. erlyvideo
      01.09.2015 19:37

      только это не mp4, а h264. mp4 это контейнер, в который можно положить h264.


  1. itcoder
    01.09.2015 23:06

    Ждем код демона на github.
    А зачем через exec делать форки потоков, почему не взяли тот же supervosor? указав нужное количество потоков которые вычитывали очередь, по моему так было бы надежнее.


    1. prodex
      02.09.2015 07:01
      +1

      Форк через exec со своей задачей тоже справляется. Если будет лагать, то посмотрю в сторону supervosor.


  1. TimsTims
    02.09.2015 08:52
    +1

    А вы уверены, что 7гбит вам хватает? Может вы как-раз и не растете и пользователи от вас уходят, потому-что у остальных тормозит?
    Всё согласено систематической ошибки выжившего https://ru.m.wikipedia.org/wiki/Систематическая_ошибка_выжившего

    И разве вам под рост проекта не нужны резервные мощности? Или вы уже поставили точку и роста не ожидаете?


    1. prodex
      02.09.2015 12:39

      Мы отслеживаем статистику по сайту и статистику загруженности серверов. Динамика прироста после внедрения еще не изменилась, растем как раньше. Но при этом проблема с нерабочими видео решена. Теперь не страшно, если «партнер» удалит у себя видео или банально ляжет.

      По примерной оценке размер видео был 4-5TB и максимальный порт в час пик около 5-7Gbit/s
      Данные показатели рассчитывали для основных сайтов «партнеров». Сейчас начинаем загружать остальных, поэтому на подходе еще несколько серверов. Плюс с 1Gbit серверами, что мы их можем добавлять по мере необходимости.

      Если суммарный канал будет более 20-30Gbit/s, то сделаю расчеты для серверов с портом 10Gbit/s.


  1. Aquary
    02.09.2015 09:33
    +1

    Интересный подход с группами — очень востребованный сценарий. Главная проблема — с приоритизацией и в последующим ранжированием видео между группами, создается определённый оверхед на все эти операции.
    Обратите внимание на подход с балансировкой VOD между эдж-серверами, описанный в этой статье.
    Здесь эджи сами подкачивают чанки по мере необходимости, а настройка параметров объёма и времени хранения даёт возможность избегать хранения неиспользуемых данных.
    То есть вопрос выбора востребованных и популярных фильмов и роликов решается автоматически — зритель голосует просмотрами, непопулярное видео уходит в /dev/null, ориджин при этом раздаёт только востребованные файлы на эджи.
    Кстати, выше BasilioCat верно заметил, что при раздаче через псевдостриминг плеер зачастую просто выкачивает ведь файл. Скорости сейчас хорошие и если зритель решил закрыть кино через 20 минут и пойти спать — к тому времени скачается весь файл целиком. Вот вам оверхед по трафику. В случае применения описанного подхода — подкачка нужных файлов и выставления параметров хранения, плюс использование чанков HLS или DASH — фрагменты непопулярного кино будут выкачиваться только в нужном для просмотра объеме.


    1. BasilioCat
      02.09.2015 10:44

      Архитектура origin-edge себя оправдывает в некоторых случаях (список не полный):
      — центральное (нераспределенное) хранилище
      — малое количество контента, но большой трафик
      При этом построение системы эджей, часть из которых отдает популярное видео с быстрых носителей, а часть (менее популярное) с медленных, а совсем непопулярное отдается вообще в ориджинов (нет смысла кэшировать) — довольно сложная задача, нужен интеллектуальный балансировщик запросов. Сейчас, со снижением стоимости SSD, уровень edge с жесткими дисками можно вообще говоря и пропустить, оставив один уровень, но проблему с маловостребованным контентом это не решает — на edge-cерверах он не нужен. Также, egde сервера будут хранить лишний объем файлов, если они занимаются только кэшированием, а подготовкой контента (mp4->HLS) занимается origin.

      Если система раздает видео с серверов, где оно и хранится (распределенное хранилище), то такая система лучше масштабируется — просто добавляется очередная пачка серверов. Также сервера более универсальны — при отдаче файлов по HTTP процессор используется мало, но его можно использовать для перекодирования видео.


      1. Aquary
        02.09.2015 16:07

        Если система раздает видео с серверов, где оно и хранится (распределенное хранилище), то такая система лучше масштабируется — просто добавляется очередная пачка серверов.


        Всё это тоже правильно, но вы упускаете вариант, при котором зрители физически находятся далеко. Сервер в Москве, зритель на Камчатке — и можно скольо угодно ставить серверов в датацентре, но камчадалам от этого не легче. Тут помимо экономии трафика (а он там дорогой), вы экономите время загрузки. При таком раскладе эджи крайне нужны. Как их наполнять — тут да, варинты есть, конечно. Можно по описаной в статье схеме, можно просто копировать всё содержимое один раз и всё. Но вариант в любом случае живой, его нельзя сбрасывать со счетов.


        1. BasilioCat
          02.09.2015 17:03

          Никто не мешает хранить какую-то часть контента (популярную в данном регионе) на удаленной площадке, а остальное тянуть с центральной. Пусть даже в режиме проксирования, если каналы позволяют. Если объем контента небольшой, так и полную копию можно хранить. А если большой, то толку от одного сервера с кэшом на 2Тб будет только для очень популярных файлов. Распределенное хранилище ничем не хуже кэша, а вот управление им гораздо более гибкое, чем LRU в nginx. Да и нет оверхеда на хранение потоков в HLS+HDS+plain


    1. prodex
      02.09.2015 12:50

      За статью спасибо.

      Кстати, выше BasilioCat верно заметил, что при раздаче через псевдостриминг плеер зачастую просто выкачивает ведь файл.
      Я думал, что это зависит от плеера. Что мешает плееру выкачать поток HLS полностью?


      1. erlyvideo
        02.09.2015 12:52

        если это флеш-плеер, то это дело его автора. Если это не флеш-плеер, то мешает то, что так никто не делает.


    1. prodex
      02.09.2015 13:07

      Главная проблема — с приоритизацией и в последующим ранжированием видео между группами, создается определённый оверхед на все эти операции.
      Если эдж-сервера заполнять динамически в зависимости от популярности видео в текущий момент, то согласен, что создается оверхед. В моем случае, видео закрепляется за одной группой, в которую входят эдж сервера. Поэтому видео записывается на эдж сервер один раз, и то по локальной сети в 1Gbit (чтобы не забивать внешний порт для раздачи).


      1. Aquary
        02.09.2015 16:10

        Да, в вашем случае с локальной сетью это отлично работает. Просто только столкнётесь с необходимостью сделать географическое разнесение контента — надо будет что-то другое придымывать. Но такое возникает не у всех, конечно.


        1. prodex
          02.09.2015 19:00
          +1

          Стараемся решать проблемы по мере поступления)


  1. Invision70
    02.09.2015 09:52

    Порноиндустрия прожорлива по трафику… )


    1. esc
      02.09.2015 12:03
      +1

      В порноиндустрии такими объемами уже давно не оперируют. Как минимум, на порядок больше.


  1. minalexpro
    03.09.2015 06:40

    А покажите ссылку на площадку, в статье не нашел. Можно в личку