Опыт реализации Open Source OTT TV CDN решения из 2015 года

06 Feb 2022 - freefd - DmitryZaytsev

Share on:

В основе CDN 1 лежит принцип географически более близкого расположения серверов с контентом к пользователю, что увеличивает скорость доставки контента и снижает нагрузку на первичный источник (Origin).

Внимание:

Упрощённое объяснение разницы между классическим распространением контента с единичного сервера:

NOCDN

и через CDN:

CDN

Составляющие CDN для ACME

Функциональные

В иерархии CDN реализации для ACME можно выделить следующие функциональные составляющие:

Origin Streamer

Физически представляет собой сервер с большим количеством 7200 RPM 7 дисков для хранения и раздачи контента. Контент на стримеры доставляется по NFS 8 10G с Packager’ов 9 (EN). То есть на серверах находится prepackaged контент, уже разбитый на сегменты (chunks). Раздаёт media m3u8 10 манифест и контент для конечного пользователя.

Внимание:
На 2022 год это не самый лучший вариант стриминга. Например, можно использовать пакетированиее на лету с помощью NGINX-based VOD Packager 11 (EN)

CDN Precache

Выполняет две функции:

CDN Cache

Горизонтально масштабируемая единица комплекса, непосредственно раздающая контент пользователям. Представляет собой виртуальный или физический сервер с умеренным количеством RAM, куда кешируется контент в момент проксирования пользовательских запросов, и 1G или 10G+ Ethernet, в зависимости от технических возможностей сервера.

Router

Каналообразующая единица комплекса, принимающая анонсы BGP Anycast 13 от ближайших CDN Cache’ров, маршрутизирующая и балансирующая пользовательский трафик до них. Также организовывает отказоустойчивость решения, выбирая для пользовательского трафика новый путь до CDN Cache’ров в случае выхода из строя ближайших.

Программные

Вся программная реализация CDN использует Open Source продукты:

Операционная Система

В качестве платформы все серверы, за исключением Origin Streamers, используют CentOS 14 (EN) - дистрибутив Linux, основанный на коммерческом Red Hat Enterprise Linux компании Red Hat и совместимый с ним. Origin Streamer’ы используют Red Hat Enterprise Linux 15 (EN).

Внимание:
В результате принятых Red Hat решений, c 2021 года CentOS 8 трансформирован в CentOS Stream 16 (EN) и считается платформой для разработки изменений, включаемых затем в RHEL редакцию. Более не рекомендуется как промышленная полноценная замена RHEL.

Кеширующий HTTP-прокси сервер

Доставку OTT-контента и кеширование в процессе проксирования выполняет Nginx 17 - HTTP-сервер и обратный прокси-сервер, почтовый прокси-сервер, а также TCP/UDP прокси-сервер общего назначения. Серверы Nginx присутствуют на Origin Streamer’ах, CDN Precache’рах и CDN Cache’рах.

Демон динамической IPv4/IPv6 маршрутизации

Для задач динамической маршрутизации IPv4/IPv6 на платформе Linux в CDN для ACME используется The BIRD Internet Routing Daemon 18 (EN). С его помощью CDN Cache’ры анонсируют BGP Anycast IP.

Внимание:
В 2022 году, пожалуйста, используйте BIRD2 реализацию.

Система мониторинга daemon’ов

Monit 19 (EN) выполняет локальных мониторинг сервисов, позволяет выполнять действия при достижении определенных событий. Отслеживает работоспособность Nginx.

Система мониторинга

Zabbix 20 отслеживает статусы сервисов ОС серверов и ключевые метрики комплекса. Считает статистику по трафику для Live/VoD 21/PVR, Cache Hit Ratio 22 (EN), утилизацию кеша серверов, трафик из/в Origin.

Внимание:
В 2022 году имеет смысл рассмотреть альтернативы Zabbix, например, Prometheus 23 (EN).

Архитектурная схема CDN для ACME

ACME CDN Architecture

Как видно на схеме, коммуникации Cache <-> Precache выполняются в формате Active-Active.

Диаграмма последовательности потоков трафика пользовательского устройства

Для доставки фрагментов видеопотока используется классическая схема для HLS/DASH с двумя m3u8 манифестами: master и media.

HLS/Dash ABR

Подробней про HLS/DASH и ABR можно прочесть в What’s HTTP Live Streaming 24 (EN). Общую последовательность запросов можно представить как

ACME CDN Traffic Flow

Важно заметить, что master и media манифесты не всегда обязан предоставлять Origin, порой это может быть совершенно отдельный ресурс. В этом случае Origin от конечного пользователя полностью скрыт CDN.

Настройки программного обеспечения комплекса

Упрощённая сетевая схема примера подключения Cache сервера к Router

ACME CDN Cache to Router connectivity

BGP: Juniper MX

Примеры настроек BGP 25- и BFD 26 (EN)-сессий для Juniper MX 27 в классическом show configuration формате:

protocols {
    ...
    bgp {
        ...
        group tv-cdn {
            type external;
            description "-- OTT TV CDN Servers --";
            mtu-discovery;
            log-updown;
            import import-tv-cdn;
            family inet {
                unicast {
                    prefix-limit {
                        maximum 5;
                        teardown idle-timeout 5;
                    }
                }
            }
            export export-default;
            multipath;
            neighbor 198.51.100.178 {
                description "-- msk-cache-01.tv.acme.tld";
                peer-as 64511;
                bfd-liveness-detection {
                    minimum-interval 250;
                }
            }
            ...
        }
        ...
    }
}
policy-options {
    prefix-list default {
        0.0.0.0/0;
    }
    policy-statement export-default {
        term default-route {
            from {
                prefix-list default;
            }
            then accept;
        }
        then reject;
    }
    policy-statement import-tv-cdn {
        term reject-default-route {
            from {
                route-filter 0.0.0.0/0 exact;
            }
            then reject;
        }
        term reject-multicast {
            from {
                route-filter 224.0.0.0/4 orlonger;
            }
            then reject;
        }
        term bgp {
            from protocol bgp;
            then {
                community set type-aggregatable-customer;
                community add acme-msk;
                accept;
            }
        }
    }
}

Опция BGP Multipath 28 (EN) используется для отказоустойчивости и балансировки пользовательского трафика между несколькими серверами в локации. BFD-сессия настроена для более быстрого разрыва BGP-сессии и перестройки таблицы маршрутов в случае недоступности Cache сервера.

BGP: CDN Cache

Пример настроек BIRD для CDN Cache’ров:

protocol device {
    scan time 10;
}

protocol direct {
    interface "lo*";
}

protocol bgp msk_cache_01_tv_pop01_public_bgp {
    description "-- msk-r1-pop01.acme.tld irb.1010";
    router id 198.51.100.178;
    local as 64511;
    neighbor 198.51.100.177 as 64496;
    export where source = RTS_DEVICE;
    import all;
    source address 198.51.100.178;
    next hop self;
}

protocol bfd msk_r1_pop01_bfd {
        interface "eth0" {
                interval 250 ms;
                multiplier 3;
        };
        neighbor 198.51.100.177;
}

log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug };

BIRD каждые 10 секунд будет перечитывать список интерфейсов и выбирать из них лишь lo интерфейсы, на которых как secondary добавлен Anycast IP адрес 198.51.100.190. Анонсируются в BGP лишь Directly Connected интерфейсы (RTS_DEVICE), которыми и являются lo. Импортируются в виртуальную таблицу BGP любые префиксы от пира.

BFD работает на интерфейсе eth0, настройки interval и multiplier идентичны настройкам Juniper MX.

ОС: CDN Cache, CDN Precache

Как известно, на подключениях 1G используется кодирование 8b/10b 29 (EN), то есть, на 10 байт переданной информации приходится 8 байт данных. Накладные расходы в объёмах переданного трафика в единицу времени для 1G интерфейса могут достигать 20%. Более предпочтительно использовать 10G+ интерфейсы, в которых используется уже 64b/66b 30 (EN) кодирование и накладные расходы не превышают 3-4%.

В зависимости от реализации, средняя продолжительность TS-фрагмента потока в HLS/DASH может быть от 2 до 15 секунд 31 (EN). В реализации используемой ACME платформы OTT Middleware продолжительность одного фрагмента составляет 8 секунд, а размер TS-фрагмента не превышает 9 MB, в зависимости от выбранного клиентом профиля. Средний размер фрагмента около 2.2 MB.

Учитывая размер фрагмента, имеет смысл включать Jumbo Frame 32, но только на тех серверах, которые коммутируются с сетевым оборудованием с включенным Jumbo Frame.

При подключении сервера к каналообразующему оборудованию через интерфейс 1G необходимо обратить внимание на возможность работы оборудования с Jumbo Frame. Например, некоторые SFP-трансиверы 1000BASE-T 33 (они же SFP-T), имеют Hardware MTU в 1500 байт и любые попытки задействовать Jumbo Frame на стороне сервера не дадут результатов.

Типовые настройки сетевого интерфейса для CentOS 7:

$ cat /etc/sysconfig/network-scripts/ifcfg-eth0 
TYPE="Ethernet"
BOOTPROTO="static"
DEFROUTE="yes"
PEERDNS="no"
PEERROUTES="no"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="no"
IPV6_DEFROUTE="no"
IPV6_PEERDNS="no"
IPV6_PEERROUTES="no"
IPV6_FAILURE_FATAL="no"
NAME="eth0"
UUID="55084b5b-3a68-4b2d-89c3-833cbf1f73fb"
DEVICE="eth0"
DNS1=198.51.100.6
DNS2=203.0.113.6
DOMAIN="tv.acme.tld"
SEARCH="tv.acme.tld"
ONBOOT="yes"
IPADDR=198.51.100.178
NETMASK=255.255.255.248
GATEWAY=198.51.100.177
MTU=9000

Дополнительно следует увеличить размер очереди передачи сетевого интерфейса txqueuelen 34 (EN) (Transmit Queue Length) до значений, больших значения по умолчанию. К сожалению, классический параметр ETHTOOL_OPTS не позволяет изменять этот параметр (на 2015 год), поэтому значение txqueuelen будет задаваться через udev при загрузке ОС:

$ cat /etc/udev/rules.d/50-custom-txqueuelen.rules 
KERNEL=="eth*", RUN+="/sbin/ip link set %k txqueuelen 10000"

Не менее важной является корректировка настроек ядра Linux через sysctl 35:

$ cat /etc/sysctl.conf
# Максимальное количество file-handlers, которое система сможет утилизировать
fs.file-max=100000

# Использовать полный диапазон портов
net.ipv4.ip_local_port_range = 1024 65535

# Выключить быструю утилизацию сокетов в состоянии TIME_WAIT.
net.ipv4.tcp_tw_recycle = 0

# Разрешить переиспользовать уже существующие сокеты в состоянии TIME_WAIT
net.ipv4.tcp_tw_reuse = 1

# По 16MB на сокет для передачи и приёма данных
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# Максимальное число запоминаемых запросов на соединение, 
# для которых не было получено подтверждения от клиента
net.ipv4.tcp_max_syn_backlog = 4096

# Включает SYN Cookies, защита от SYN флуда
net.ipv4.tcp_syncookies = 1

# Максимальное количество "backlogged" сокетов
net.core.somaxconn = 2048

# Максимальное количество пакетов, взятое со всех интерфейсов за один цикл поллинга
net.core.netdev_budget = 600

# Отключить TCP Selective Acknowledgments (SACK) для высокопроизводительной сети
net.ipv4.tcp_sack = 0

# Изменить приёмные буферы для сокетов
net.ipv4.tcp_rmem = 16384 349520 16777216

Очень важно держать параметр net.ipv4.tcp_tw_recycle выключенным, иначе пользователи не смогут смотреть контент одновременно с нескольких устройств с одного IP.

Все логи Nginx шлёт по syslog на хост msk-cache-analytics01.acme.tld. Эта функциональность появилась в общедоступном Nginx появилась в версии 1.7.1.

На всех серверах групп CDN Precache и CDN Cache используется tmpfs 36 для размещения кешируемых Nginx файлов. Для CDN Cache’ров:

$ grep tmpfs /etc/fstab
tmpfs    /var/cache/nginx/ram    tmpfs   defaults,nodev,nosuid,size=7G 0 0

Для CDN Precache’ров:

$ grep tmpfs /etc/fstab 
tmpfs    /var/cache/nginx/ram    tmpfs   defaults,nodev,nosuid,size=14G 0 0

Monit: CDN Cache, CDN Precache

Основой текущей реализации CDN ACME является Nginx и от стабильности его работы зависит качество услуги. Несмотря на то, что используется стабильная ветка Nginx, в продуктивных системах могут происходить коллизии. В качестве локального сервиса слежения за работоспособностью Nginx выбран Monit из-за своей компактности и нетребовательности к ресурсам системы.

$ sudo monit status
The Monit daemon 5.14 uptime: 4d 22h 9m 

Process 'nginx'
  status                            Running
  monitoring status                 Monitored
  pid                               991
  parent pid                        1
  uid                               0
  effective uid                     0
  gid                               0
  uptime                            4d 22h 9m 
  children                          5
  memory                            1.4 MB
  memory total                      24.4 MB
  memory percent                    0.0%
  memory percent total              0.3%
  cpu percent                       0.0%
  cpu percent total                 9.4%
  port response time                0.000s to [127.0.0.1]:80 type TCP/IP protocol DEFAULT
  data collected                    Tue, 03 May 2016 23:09:57

System 'msk-cache-01.tv.acme.tld'
  status                            Running
  monitoring status                 Monitored
  load average                      [0.36] [0.47] [0.49]
  cpu                               3.7%us 7.8%sy 0.0%wa
  memory usage                      269.9 MB [3.3%]
  swap usage                        0 B [0.0%]
  data collected                    Tue, 03 May 2016 23:09:57

Monit работает на localhost:2812, доступ к управлению разрешён с localhost:

$ cat /etc/monit.d/monit
set httpd port 2812 and
     use address localhost
     allow localhost

Параметры мониторинга Nginx включают:

logrotate: CDN Cache

Так как все Access лог-файлы шлются на удалённый сервер msk-cache-analytics01.acme.tld, а локально на CDN Cache’рах хранится только информация о кешировании, нет большого смысла хранить эти лог-файлы более двух дней:

$ cat /etc/logrotate.d/nginx 
/var/log/nginx/*.log {
        daily
        missingok
        rotate 1
        compress
        delaycompress
        notifempty
        create 644 nginx adm
        sharedscripts
        postrotate
                [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
        endscript
}

Nginx: CDN Cache

Точкой входа пользовательского трафика в CDN являются CDN Cache’ры. Настройки Nginx этих серверов выглядят следующим образом:

$ cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    log_format main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    log_format cache '$upstream_cache_status';

    log_format CDN '{"ip": "$remote_addr", "host": "$host", "path": "$request_uri", "status": "$status", "user_agent": "$http_user_agent", "length": $bytes_sent, "date": "$time_iso8601"}';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    proxy_cache_path /var/cache/nginx/ram keys_zone=ram:10m inactive=1m max_size=6656m;

    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        server_name  _;

        location / {
            root   /usr/share/nginx/html;
            return 403;
        }
    }
}

Модификации подвергся параметр worker_rlimit_nofile, изменяющий ограничения на максимальное число открытых файлов для рабочих процессов. Дополнительно был создан новый формат лога CDN, формирующий лог в формате JSON. Создана кеш-область в RAM максимальным размером в 6.5 GB параметром proxy_cache_path. Данные в кеше удаляются каждую минуту при отсутствии обращений к ним. Также стоит обратить внимание на формат логирования cache, который записывает в лог только содержимое переменной $upstream_cache_status. Этого значения достаточно для дальнейшего подсчёта cache hit ratio.

$ cat /etc/nginx/conf.d/CDN.conf 
upstream cdn.tv.acme.tld {
    # msk-precache-01.tv.acme.tld
    server 198.51.100.162:80;

    # msk-precache-02.tv.acme.tld
    server 198.51.100.166:80;

    # msk-vs-01.tv.acme.tld
    server 192.0.2.56:80 backup;

    # msk-vs-02.tv.acme.tld
    server 192.0.2.57:80 down;
}

upstream pvr01-cdn.tv.acme.tld {
    # msk-precache-01.tv.acme.tld
    server 198.51.100.162:80;

    # msk-precache-02.tv.acme.tld
    server 198.51.100.166:80;
}

upstream pvr02-cdn.tv.acme.tld {
    # msk-precache-01.tv.acme.tld
    server 198.51.100.162:80;

    # msk-precache-02.tv.acme.tld
    server 198.51.100.166:80;
}

map $http_host $upstreamSet {
    hostnames;
    pvr01-cdn.tv.acme.tld    "pvr01-cdn.tv.acme.tld";
    pvr01-cdn.tv.acme.tld:80 "pvr01-cdn.tv.acme.tld";
    pvr02-cdn.tv.acme.tld    "pvr02-cdn.tv.acme.tld";
    pvr02-cdn.tv.acme.tld:80 "pvr02-cdn.tv.acme.tld";
    default "cdn.tv.acme.tld";
}

server {
    listen 80;
    server_name pvr01-cdn.tv.acme.tld pvr02-cdn.tv.acme.tld cdn.tv.acme.tld;

    # msk-cache-analytics01.acme.tld
    access_log syslog:server=203.0.113.221:514,facility=local7,tag=nginx,severity=info CDN;

    access_log /var/log/nginx/cache.log cache;
    error_log /var/log/nginx/error.log;

    location ~* \.(m3u8)$ {
        proxy_cache off;
        expires -1;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://$upstreamSet;
    }

    location / {
        index plst.m3u8;

        types {
            application/vnd.apple.mpegurl m3u8;
            video/mp2t ts;
        }

        proxy_cache ram;
        proxy_cache_key $host$uri;
        proxy_cache_valid 5m;
        proxy_temp_path /var/cache/nginx/ram/temp;
        proxy_store_access user:rw group:rw all:r;
        proxy_method GET;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_pass http://$upstreamSet;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

В конфигурации виртуального хоста CDN Cache’ра для выбора upstream группы задействован механизм map, который подставляет в proxy_pass в переменную $upstreamSet требуемые значения. Виртуальный сервер обслуживает имена pvr01-cdn.tv.acme.tld, pvr02-cdn.tv.acme.tld, cdn.tv.acme.tld. Access лог-файлы шлются на удалённый хост msk-cache-analytics01.acme.tld по протоколу syslog. Файлы m3u8 не кешируются, остальные файлы кешируются на 5 минут. Ключом занесения файла в кеш является $host$uri, так как часть $query_string видоизменяется в процессе жизни элемента HLS/DASH потока. Дополнительно переписывается поле Connection и включается HTTP/1.1 для задействования механизма Keep-Alive, позволяя сократить количество соединений между пользовательским устройством и CDN Cache’ром, а также между CDN Cache’ром и CDN Precache’ром.

Особое внимание стоит обратить на блок map, в котором присутствуют описания хостов как с указанием порта, так и без. Это решение требуется для iOS (iPhone, iPad), которая по умолчанию в заголовок Host при запросе подставляет порт, даже если это 80 порт.

Nginx: CDN Precache

Само появление CDN Precache’ров обязано лицензионным ограничениям платформы OTT Middleware по гигабитам трафика с Origin Streamer’ов. Nginx на CDN Precache’рах отрабатывает логику отказоустойчивости решения, выбора Origin Streamer’а и распределения трафика между ними по разного вида услугам:

Основная конфигурация Nginx на CDN Precache’ре практически не отличается от таковой на CDN Cache’ре:

$ cat /etc/nginx/nginx.conf 
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 2048;
}

http {
    log_format main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    log_format CDN '{"ip": "$remote_addr", "host": "$host", "path": "$request_uri", "status": "$status", "user_agent": "$http_user_agent", "length": $bytes_sent, "date": "$time_iso8601"}';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    proxy_cache_path /var/cache/nginx/ram keys_zone=ram:10m inactive=1m max_size=13824m;

    include /etc/nginx/conf.d/*.conf;
}

Отличия заключаются в размере кеша в 13.5 GB и отсутствии default виртуального хоста. Основная конфигурация:

$ cat /etc/nginx/conf.d/CDN.conf 
upstream cdn.tv.acme.tld {
    # msk-vs-01.tv.acme.tld
    server 192.0.2.56:80;

    # msk-vs-02.tv.acme.tld
    server 192.0.2.57:80 down;

    keepalive 1024;
}

upstream pvr01-cdn.tv.acme.tld {
    # msk-vs-01.tv.acme.tld
    server 192.0.2.56:80;
}

upstream pvr02-cdn.tv.acme.tld {
    # msk-vs-02.tv.acme.tld
    server 192.0.2.57:80;
}

map $http_host $upstreamSet {
    hostnames;
    pvr01-cdn.tv.acme.tld "pvr01-cdn.tv.acme.tld";
    pvr02-cdn.tv.acme.tld "pvr02-cdn.tv.acme.tld";
    default "cdn.tv.acme.tld";
}

server {
    listen 80 default_server;
    server_name _;

    access_log off;
    error_log /var/log/nginx/msk-precache-01.tv.acme.tld.error.log;

    location ~* \.(m3u8)$ {
        proxy_cache off;
        expires -1;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404;
        proxy_pass http://$upstreamSet;
    }

    location / {
        index plst.m3u8;

        types {
            application/vnd.apple.mpegurl m3u8;
            video/mp2t ts;
        }

        proxy_cache ram;
        proxy_cache_key $host$uri;
        proxy_cache_valid 5m;
        proxy_temp_path /var/cache/nginx/ram/temp;
        proxy_store_access user:rw group:rw all:r;
        proxy_method GET;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404;
        proxy_pass http://$upstreamSet;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

Применяются все те же приёмы, которые использовались для CDN Cache’ров, но теперь upstream группы содержат лишь хосты Origin Streamer’ов.

PVR и виртуальные кластеры OTT Middleware

Для разделения PVR 37 каналов по отдельным стримерам и более гибкого масштабирования услуг реализованы виртуальные кластеры:

pvr01-cdn.tv.acme.tld привязан к msk-vs-01.tv.acme.tld Origin Streamer’у, а pvr02-cdn.tv.acme.tld - к msk-vs-02.tv.acme.tld. Это позволяет разнести пользовательскую нагрузку между Origin Streamer’ами по услуге PVR, так как услуга PVR вызывает большую IO на дисковую подсистему Origin Streamer’ов, и, при необходимости, осуществить резервирование услуг по отдельности.

При запросе PVR контента Service Gateway sgw.tv.acme.tld в составе OTT Middleware (msk-sgw-01.tv.acme.tld и msk-sgw-02.tv.acme.tld) отдаёт абоненту в плейлисте ссылку pvr01-cdn.tv.acme.tld или pvr02-cdn.tv.acme.tld, в зависимости от того, на каком Origin Streamer’е находится контент. Абонент обращается на общий адрес CDN cdn.tv.acme.tld и попадает на CDN Cache’ры, далее запрос проксируется на CDN Precache’ры. CDN Precache’ры согласно настроенным правилам перенаправляют запрос по доменному имени либо на msk-vs-01.tv.acme.tld, либо на msk-vs-02.tv.acme.tld.

Мониторинг

Внимание:
В 2022 году имеет смысл рассмотреть альтернативы Zabbix, например, Prometheus. Все изображения в тексте соответствуют таковым для 2016 года.

Для мониторинга характеристик CDN используется Zabbix с агентом на хостах. С каждого CDN Cache’ра и CDN Precache’ра помимо стандартных метрик, дополнительно снимаются метрики утилизации кеша Nginx, общее количество дискового пространства кеша Nginx, эффективность кеширования.

Создан хост cdn.tv.acme.tld с суммирующими данные с CDN Cache’ров/CDN Precache’ров элементами данных: ACME CDN Summary Host

CDN

Из суммируемого элемента данных по входящему трафику:

ACME CDN Total Network Incoming

и суммируемого элемента данных по исходящему трафику:

ACME CDN Total Network Outgoing

строится основной график потребления трафика в CDN:

ACME CDN Total Networking

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

Существует и общий суммирующий график утилизации Cache в CDN:

ACME CDN Cache Free

Cache Hit Ratio

Для всех CDN Cache’ров снимаются значения Cache Hit Ratio в процентном отношении:

$ cat /etc/zabbix/zabbix_agentd.d/userparams.conf 
UserParameter=cache.ratio[*],echo "scale=2; $(/bin/grep HIT /var/log/nginx/cache.log | /usr/bin/wc -l)*100/$(/bin/grep -v -- - /var/log/nginx/cache.log | /usr/bin/wc -l)" | /usr/bin/bc

По снятым значениям для каждого CDN Cache’ра строится график:

ACME CDN Cache Hit Ratio

Origin

Не менее важным является график трафика из/в Origin Streamer’ы, так как лицензирование платформы определяется количеством гигабит, потребляемых с Origin Streamer’ов:

ACME CDN Origin Total Traffic

График строится идентичным образом из двух суммирующих элементов данных: элемента данных входящего трафика с CDN Precache’ров:

ACME CDN Origin Network Incoming

и элементов данных исходящего трафика с CDN Precache’ров:

ACME CDN Origin Network Outgoing

Помимо этого, с каждого Origin Streamer’а снимаются значения по объёмам трафика услуг Live/PVR/VoD:

ACME CDN Origin Services Traffic

Диагностика

Внимание:
В 2022 году для хранения логов имеет смысл отказаться от Syslog в пользу более гибких инструментов. Например, связка Nginx JSON logs + Fluentd + Apache Kafka + ClickHouse позволяет получить обработку логов в режиме реального времени и эффективное по месту хранение.

Для облегчения диагностики работоспособности CDN логи с CDN Cache’ров шлются на хост msk-cache-analytics01.acme.tld по протоколу syslog.

В качестве примера простейшей диагностики можно рассмотреть поиск по IP клиента CDN Cache’ра, который с 21 до 22 часов вечера приземлял трафик пользователя услуги PVR на платформе iOS:

$ grep 198.18.18.140 /var/log/remote/2016/05/15/*_21_access.log | grep -i pvr | grep -i apple | head -5
/var/log/remote/2016/05/15/msk-cache-03.tv.acme.tld_21_access.log:{"ip": "198.18.18.140", "host": "pvr01-cdn.tv.acme.tld", "path": "/pvr/id119_ACME_SG--tnt/02/c_1162603100204372.ts", "status": "200", "user_agent": "AppleCoreMedia/1.0.0.13E238 (iPad; U; CPU OS 9_3_1 like Mac OS X; ru_ru)", "length": 1350008, "date": "2016-05-15T21:02:34+03:00"}
/var/log/remote/2016/05/15/msk-cache-03.tv.acme.tld_21_access.log:{"ip": "198.18.18.140", "host": "pvr01-cdn.tv.acme.tld", "path": "/pvr/id119_ACME_SG--tnt/02/c_1162603100204373.ts", "status": "200", "user_agent": "AppleCoreMedia/1.0.0.13E238 (iPad; U; CPU OS 9_3_1 like Mac OS X; ru_ru)", "length": 1130888, "date": "2016-05-15T21:02:36+03:00"}
/var/log/remote/2016/05/15/msk-cache-03.tv.acme.tld_21_access.log:{"ip": "198.18.18.140", "host": "pvr01-cdn.tv.acme.tld", "path": "/pvr/id119_ACME_SG--tnt/01/plst.m3u8?chanId=119&startDate=15052016113500&endDate=15052016133500&curPos=15052016113500", "status": "200", "user_agent": "AppleCoreMedia/1.0.0.13E238 (iPad; U; CPU OS 9_3_1 like Mac OS X; ru_ru)", "length": 35920, "date": "2016-05-15T21:02:37+03:00"}
/var/log/remote/2016/05/15/msk-cache-03.tv.acme.tld_21_access.log:{"ip": "198.18.18.140", "host": "pvr01-cdn.tv.acme.tld", "path": "/pvr/id119_ACME_SG--tnt/01/c_1162603100204004.ts", "status": "200", "user_agent": "AppleCoreMedia/1.0.0.13E238 (iPad; U; CPU OS 9_3_1 like Mac OS X; ru_ru)", "length": 861207, "date": "2016-05-15T21:02:37+03:00"}
/var/log/remote/2016/05/15/msk-cache-03.tv.acme.tld_21_access.log:{"ip": "198.18.18.140", "host": "pvr01-cdn.tv.acme.tld", "path": "/pvr/id119_ACME_SG--tnt/02/plst.m3u8?chanId=119&startDate=15052016113500&endDate=15052016133500&curPos=15052016113500", "status": "200", "user_agent": "AppleCoreMedia/1.0.0.13E238 (iPad; U; CPU OS 9_3_1 like Mac OS X; ru_ru)", "length": 35920, "date": "2016-05-15T21:02:38+03:00"}

Пользователь с IP 198.18.18.140 на устройстве Apple iPad с русскоязычной версией iOS 9.3.1, смотревший PVR канала ТНТ, приземлялся на сервере msk-cache-03.tv.acme.tld. Дополнительно можно сказать, учитывая информацию об имени PVR сервера, что пользователь уходил на Origin Streamer msk-vs-01.tv.acme.tld.

Для удобства чтения JSON-логов Nginx на сервере msk-cache-analytics01.acme.tld предустановлена утилита jq 38 (EN).

$ grep -h 198.18.18.140 /var/log/remote/2016/05/15/*_21_access.log | grep -i pvr | grep -i apple | head -1 | jq .
{
  "ip": "198.18.18.140",
  "host": "pvr01-cdn.tv.acme.tld",
  "path": "/pvr/id119_ACME_SG--tnt/02/c_1162603100204372.ts",
  "status": "200",
  "user_agent": "AppleCoreMedia/1.0.0.13E238 (iPad; U; CPU OS 9_3_1 like Mac OS X; ru_ru)",
  "length": 1350008,
  "date": "2016-05-15T21:02:34+03:00"
}

Ссылки

1. Content Delivery Network
2. Over the Top
3. Internet Service Provider
4. Связующее программное обеспечение
5. Автономная система
6. Acme Corporation
7. Обороты в минуту
8. Network File System
9. Streaming Packagers [EN]
10. M3U формат
11. NGINX-based VOD Packager [EN]
12. RAM
13. BGP Anycast
14. CentOS [EN]
15. Red Hat Enterprise Linux [EN]
16. CentOS Stream [EN]
17. Nginx
18. The BIRD Internet Routing Daemon [EN]
19. Monit [EN]
20. Zabbix
21. Видео по запросу
22. Cache Hit Ratio [EN]
23. Prometheus [EN]
24. What’s HTTP Live Streaming [EN]
25. Border Gateway Protocol
26. Bidirectional Forwarding Detection [EN]
27. Универсальные платформы маршрутизации серии MX
28. BGP Multipath [EN]
29. 8b/10b Encoding [EN]
30. 64b/66b Encoding [EN]
31. Optimal Adaptive Streaming Formats MPEG-DASH & HLS Segment Length [EN]
32. Jumbo-кадр
33. Gigabit Ethernet
34. Queueing in the Linux Network Stack [EN]
35. Sysctl утилита
36. Файловой хранилище tmpfs
37. Цифровой видеорекордер
38. Command-line JSON processor jq [EN]

Tags: open source ott tv cdn