Ce billet est le dernier d’une série de 5 :
- introduction et considérations pour le SSTIC ;
- l’architecture de streaming ;
- la chaîne de capture audio/vidéo sur place ;
- le transcodage des flux en différentes qualités ;
- les serveurs frontaux accédés par les internautes.
Prérequis
Bande passante
Pour un serveur frontal, contrairement au serveur de transcodage, la seule caractéristique importante est le débit disponible. Comptez une moyenne de 2 Mbits/s par client pour avoir de la marge.
Matériel
Un serveur dédié avec un CPU Intel Atom, ARM ou équivalent et une liaison gigabit non garantie seront largement suffisant. Avec des chunks de 5 secondes et 500 ou 1000 clients, il subira 100 à 200 hits/s environ, ce qui reste gérable par des configurations très modestes (et c’est paramétrable).
Il est ainsi possible de louer des serveurs «jetables» pour avoir un pool de frontaux conséquent, ou de bénéficier d’un peering plus favorable vers certains FAI en variant les hébergeurs pour ces frontaux.
Mise en place
La mise en place d’un frontal est très simple et peut même se faire en 5 minutes. Pour les habitués, la procédure est quasiment identique à la mise en place d’un relai, à la différence près que le frontal n’ira pas chercher le flux, mais que le serveur de transcodage lui poussera le flux spontanément.
Routage RTMP et HLS
Reprenons le routage vidéo mis en place sur le serveur de transcodage :
Pour le frontal, il s’agit uniquement de créer l’application hls
en bas à droite. Elle servira les flux RTMP directement aux clients finaux, en plus de découper le flux en chunks placés sur le disque dur pour être servis en HTTP. Le flux source, lui, sera poussé en RTMP par le serveur de transcodage, comme indiqué sur la droite du schéma.
Compilation de nginx avec son module RTMP
La procédure sera la même que pour le serveur de transcodage :
apt-get install build-essential libpcre3 libpcre3-dev libssl-dev unzip
wget https://nginx.org/download/nginx-1.16.0.tar.gz
wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
tar zxvf nginx-1.16.0.tar.gz
unzip master.zip
cd nginx-1.16.0
./configure --add-module=../nginx-rtmp-module-master --with-http_ssl_module
make && make install
Vous devez toujours créer les dossiers nécessaires :
mkdir -p /var/www/stat /var/www/hls /var/www/player
chown -R nobody /var/www/stat /var/www/hls /var/www/player
Copiez aussi stat.xsl
depuis le dossier du module rtmp dans /var/www/stat/
:
cp ../nginx-rtmp-module-master/stat.xsl /var/www/stat/
nginx
est désormais installé dans /usr/local/nginx/
. Sa configuration est située dans /usr/local/nginx/conf/nginx.conf
.
Pour démarrer le serveur en tâche de fond, lancez la commande :
/usr/local/nginx/sbin/nginx
Pour le stopper complètement, par exemple en cas de modification de la configuration RTMP, lancez :
/usr/local/nginx/sbin/nginx -s stop
Il faut également mettre le lecteur vidéo HTML5 :
wget https://static.sstic.org/streaming2019/player.tar.gz
tar zxvf player.tar.gz -C /var/www/player
Il ne reste plus qu’à configurer nginx pour qu’il serve les fichiers HTML et les chunks vidéo.
Configuration de nginx
Techniquement, il est possible de copier-coller le fichier de configuration du serveur de transcodage. ffmpeg
n’étant pas installé, aucun flux ne sera alimenté et seule l’application RTMP hls
est utile.
Voici une configuration dédiée à l’usage en tant que serveur frontal. Elle est téléchargeable ici et la documentation des directives est accessible par là.
Il existe une différence notable par rapport à notre serveur de transcodage : la partie HTTP est accessible à tous les clients, alors que sur le serveur de transcodage elle est restreinte aux IP autorisées à des fins de debug. Sur ce dernier, il est aussi fait usage de règles iptables
pour filtrer les clients autorisés à la volée, sans redémarrer nginx
.
Utiliser iptables
pour gérer les autorisations d’accès permet de créer un fichier de configuration unique partagé entre serveurs de transcodage et frontaux.
worker_processes 1;
events {
worker_connections 1024;
}
Comme pour le transcoder, nous n’utilisons qu’un seul worker. Si vous n’utilisez pas d’options incompatibles (exec*
), vous pouvez en avoir plusieurs.
rtmp {
server {
listen 1935;
chunk_size 4096;
application hls {
# Application gérant l'écriture des _chunks_ HLS dans un path
# accessible en HTTP
live on;
hls on;
hls_path /var/www/hls;
hls_nested on;
hls_playlist_length 10m;
hls_type live;
hls_variant _low BANDWIDTH=512000;
hls_variant _mid BANDWIDTH=1024000;
hls_variant _hi BANDWIDTH=2048000;
# nombre maximum de connexions RTMP à accepter
# max_connections 512;
# attention, la vraie limite se fait au niveau de l'alias HTTP
# publication en local seulement
allow publish 127.0.0.1;
allow publish 178.33.71.43; # on autorise le serveur de transcodage (ancien)
allow publish 62.210.203.206; # on autorise le serveur de transcodage (new)
deny publish all;
# lecture pour tous
allow play all;
}
}
}
Les hls_variant
permettent de décrire les paramètres renseignés dans les playlists m3u8 générées, afin d’aider les lecteurs clients à gérer diverses choses comme la qualité du flux.
L’option la plus utile avec le lecteur HTML5 clappr est hls_playlist_length
, qui permet d’activer le «time shifting», en gros les chunks resteront disponibles plusieurs minutes sur le serveur avant d’être effacés. Les clients peuvent donc mettre le flux en pause. Le délai affiché n’est pas très précis, dans la pratique une valeur de 10 minutes nous donne 15 minutes de tampon réel.
Nous avons choisi de ne pas mettre plus de 15 minutes afin d’éviter que les clients utilisent le streaming comme un moyen d’accéder aux vidéos des présentations passées, ce qui consommerait de la bande passante au détriment des clients en direct.
# HTTP can be used for accessing RTMP stats
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
# This URL provides RTMP statistics in XML
location /stat {
rtmp_stat all;
# Use this stylesheet to view XML as web page
# in browser
rtmp_stat_stylesheet stat.xsl;
allow 127.0.0.1;
deny all;
}
location /stat.xsl {
# XML stylesheet to view RTMP stats.
# Copy stat.xsl wherever you want
# and put the full directory path here
root /var/www/stat/;
allow 127.0.0.1;
deny all;
}
location /hls {
# Serve HLS fragments
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /var/www;
add_header Cache-Control no-cache;
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
location /player {
root /var/www;
add_header Cache-Control no-cache;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
Il ne reste plus qu’à configurer la partie HTTP, qui sert les stats RTMP, le lecteur HTML5 et les chunks HLS.
Après redémarrage, le serveur frontal est prêt à recevoir des flux poussés par le serveur transcodage autorisé dans la configuration. Après quelques secondes, ils seront visibles sur la page d’accueil en HTTP.
Statistiques
La génération de statistiques d’audience en temps réel précises est compliqué, d’autant plus que l’association n’utilise aucun tracker de visiteurs.
Il est possible d’analyser les logs nginx pour repérer les clients RTMP (chercher les commandes PLAY
), mais détecter la fin de la lecture peut s’avérer problématique. De même, il est possible de détecter les GET
HTTP pour les clients HLS.
Pour rester simple, il a été choisi de générer des statistiques moyennes minute par minute, en comptant simplement le nombre de sessions TCP, le nombre de flux RTMP et le nombre d’IP différentes connectées en HTTP. Le nombre réel de clients se situe entre le nombre d’IP sur les flux RTMP/HTTP et le nombre de sessions TCP concurrentes (plusieurs clients peuvent se trouver derrière une même IP). Le nombre réel se situera beaucoup plus proche du nombre de sessions TCP concurrentes que du nombre d’IP connectées (même si avec le HTTP sans chiffrement, les proxies peuvent mettre en cache les chunks HLS).
Évolutions
Notre description technique de la mise en place va s’arrêter ici et laisser la suite des améliorations en exercice au lecteur, surtout pour qu’elles correspondent à ses besoins.
À titre d’exemple, voici ce qui est aussi mis en place ou prévu à terme pour le SSTIC.
Frontaux multiples
La manière la plus simple de mettre en place des frontaux multiples est d’utiliser le mécanisme de round-robin DNS. Cela permet de répartir la bande passante entre les frontaux, mais ne permet par exemple pas de rediriger certains clients de manière préférentielle vers l’un des frontaux. On pourrait imaginer rediriger les clients du FAI Free vers le frontal hébergé chez Online, pour des raisons de peering.
Une autre solution consiste à utiliser le javascript du lecteur HTML5 pour qu’il choisisse un frontal parmi une liste prédéfinie. Soit il le choisit au hasard, soit il le fait selon d’autres critères, dont par exemple celui du peering.
Enfin, les plus fortunés peuvent choisir une solution à base de load-balancer, ou même de CDN en y mettant en cache les chunks HLS.
TLS
La mise en place de SSL pose ses propres soucis. Si les multiples frontaux sont gérés par round-robin DNS, il est alors nécessaire de faire usages de techniques très sales pour partager la clé privée et le certificat serveur entre tous les frontaux, si tant est que l’on n’ait pas de load-balancer gérant le chiffrement.
La solution la moins coûteuse est donc de cumuler l’usage de javascript pour sélectionner un frontal avec des certificats Letsencrypt générés pour chaque serveur frontal.
Relais tiers
La mise en place de relais tiers est en réalité la configuration d’un serveur frontal supplémentaire. La différence principale réside dans le fait que la configuration de l’application hls
comprend une directive pull
pour aller chercher le flux vidéo vers un serveur source.
Ce serveur source peut être un frontal s’il publie les flux RTMP, ou le serveur de transcodage. Pour éviter d’exposer inutilement le serveur de transcodage à une saturation de bande passante, il n’est pas accessible par les clients finaux et peut du coup garantir à d’autres relais un accès privilégié.
Quelques problèmes à anticiper…
Pour conclure, on laissera une liste de quelques problèmes rencontrés avec les frontaux qui expliquent encore les choix développés dans cette série de billets :
- timeouts et retries : les flux provenant du serveur de transcodage peuvent être parfois interrompus. C’est pour cette raison qu’ils sont poussés par ce dernier, plutôt que tirés par le serveur frontal. Il retentera la connexion dès l’interruption détectée, plutôt que d’attendre un délai ;
- peering : certains clients peuvent avoir un FAI qui dispose de liens de peerings saturés vers l’hébergeur de vos serveurs frontaux. Pensez à une solution leur permettant de choisir leur serveur frontal pour limiter les ruptures de flux ;
- anticipez l’effet slashdot, surtout si vous invitez des orateurs connus. Pour le SSTIC, la capacité en débit a toujours été supérieure au double de la bande passante consommée, permettant de réagir si on constate un dépassement inattendu. Mettre un place un nouveau serveur prend 5 minutes, sans avoir besoin de mettre en place un DNS particulier. Il peut être ajouté instantanément à la liste des serveurs choisissables par le javascript du lecteur HTML5 ;
- réglez la taille des chunks HLS selon vos contraintes : limiter les hits/s sur vos frontaux, minimiser les délais pour vos clients ou être plus gentils avec la taille de leurs tampons. Référez-vous à la documentation du module nginx RTMP pour la marche à suivre.