Usando TSDuck para supervisar fluxos IP(TS).

Hoxe, hai solucións preparadas (propietarias) para supervisar fluxos IP(TS), por exemplo VB и iQ, teñen un conxunto de funcións bastante rico e normalmente os grandes operadores que se ocupan de servizos de televisión teñen tales solucións. Este artigo describe unha solución baseada nun proxecto de código aberto TSDuck, deseñado para un control mínimo dos fluxos IP(TS) mediante o contador CC (contador de continuidade) e a taxa de bits. Unha posible aplicación é controlar a perda de paquetes ou todo o fluxo a través dunha canle L2 alugada (que non se pode supervisar normalmente, por exemplo, lendo os contadores de perdas nas filas).

Moi brevemente sobre TSduck

TSDuck é un software de código aberto (licenza BSD de 2 cláusulas) (un conxunto de utilidades de consola e unha biblioteca para desenvolver utilidades ou complementos personalizados) para manipular fluxos de TS. Como entrada, pode funcionar con IP (multicast/unicast), http, hls, sintonizadores dvb, demodulador dektec dvb-asi, hai un xerador interno de fluxo TS e lectura de ficheiros. A saída pode ser escribindo nun ficheiro, IP (multicast/unicast), hls, dektec dvb-asi e moduladores HiDes, reprodutores (mplayer, vlc, xine) e drop. Pódense incluír varios procesadores de tráfico entre a entrada e a saída, por exemplo, reasignación de PID, codificación/descodificación, análise do contador CC, cálculo da taxa de bits e outras operacións típicas para fluxos TS.

Neste artigo, empregaranse como entrada os fluxos IP (multicast), utilízanse os procesadores bitrate_monitor (do nome é claro cal é) e continuidade (análise de contadores CC). Pode substituír facilmente a multidifusión IP por outro tipo de entrada compatible con TSduck.

Están dispoñibles compilacións/paquetes oficiais TSduck para a maioría dos sistemas operativos actuais. Non están dispoñibles para Debian, pero conseguimos crealos baixo debian 8 e debian 10 sen ningún problema.

A continuación, utilízase a versión TSDuck 3.19-1520, úsase Linux como sistema operativo (usouse debian 10 para preparar a solución, utilizouse CentOS 7 para uso real)

Preparando TSduck e OS

Antes de supervisar os fluxos reais, cómpre asegurarse de que TSDuck funciona correctamente e que non hai caídas no nivel da tarxeta de rede ou do SO (socket). Isto é necesario para non adiviñar máis tarde onde se produciron as caídas: na rede ou "dentro do servidor". Podes comprobar as caídas no nivel da tarxeta de rede co comando ethtool -S ethX, a axuste realízase pola mesma ethtool (normalmente, cómpre aumentar o búfer RX (-G) e ás veces desactivar algunhas descargas (-K)). Como recomendación xeral, pódese aconsellar utilizar un porto separado para recibir o tráfico analizado, se é posible, isto minimiza os falsos positivos asociados ao feito de que a caída ocorreu exactamente no porto do analizador debido á presenza doutro tráfico. Se isto non é posible (utilízase un mini-ordenador/NUC cun porto), entón é moi desexable configurar a priorización do tráfico analizado en relación co resto do dispositivo ao que está conectado o analizador. Respecto dos contornos virtuais, aquí cómpre ter coidado e poder atopar caídas de paquetes que comezan desde un porto físico e rematan cunha aplicación dentro dunha máquina virtual.

Xeración e recepción dun fluxo dentro do host

Como primeiro paso na preparación de TSDuck, xeraremos e recibiremos tráfico dentro dun único host usando netns.

Preparación do medio ambiente:

ip netns add P #создаём netns P, в нём будет происходить анализ трафика
ip link add type veth #создаём veth-пару - veth0 оставляем в netns по умолчанию (в этот интерфейс будет генерироваться трафик)
ip link set dev veth1 netns P #veth1 - помещаем в netns P (на этом интерфейсе будет приём трафика)
ip netns exec P ifconfig veth1 192.0.2.1/30 up #поднимаем IP на veth1, не имеет значения какой именно
ip netns exec P ip ro add default via 192.0.2.2 #настраиваем маршрут по умолчанию внутри nents P
sysctl net.ipv6.conf.veth0.disable_ipv6=1 #отключаем IPv6 на veth0 - это делается для того, чтобы в счётчик TX не попадал посторонний мусор
ifconfig veth0 up #поднимаем интерфейс veth0
ip route add 239.0.0.1 dev veth0 #создаём маршрут, чтобы ОС направляла трафик к 239.0.0.1 в сторону veth0

O medio ambiente está preparado. Iniciamos o analizador de tráfico:

ip netns exec P tsp --realtime -t 
 -I ip 239.0.0.1:1234 
 -P continuity 
 -P bitrate_monitor -p 1 -t 1 
 -O drop

onde "-p 1 -t 1" significa que cómpre calcular a taxa de bits cada segundo e mostrar información sobre a taxa de bits cada segundo
Iniciamos o xerador de tráfico cunha velocidade de 10 Mbps:

tsp -I craft 
 -P regulate -b 10000000 
 -O ip -p 7 -e --local-port 6000 239.0.0.1:1234

onde "-p 7 -e" significa que cómpre empaquetar 7 paquetes TS nun paquete IP e facelo duro (-e), é dicir. sempre agarde 1 paquetes TS do último procesador antes de enviar un paquete IP.

O analizador comeza a emitir as mensaxes esperadas:

* 2020/01/03 14:55:44 - bitrate_monitor: 2020/01/03 14:55:44, TS bitrate: 9,970,016 bits/s
* 2020/01/03 14:55:45 - bitrate_monitor: 2020/01/03 14:55:45, TS bitrate: 10,022,656 bits/s
* 2020/01/03 14:55:46 - bitrate_monitor: 2020/01/03 14:55:46, TS bitrate: 9,980,544 bits/s

Agora engade algunhas gotas:

ip netns exec P iptables -I INPUT -d 239.0.0.1 -m statistic --mode random --probability 0.001 -j DROP

e aparecen mensaxes coma esta:

* 2020/01/03 14:57:11 - continuity: packet index: 80,745, PID: 0x0000, missing 7 packets
* 2020/01/03 14:57:11 - continuity: packet index: 83,342, PID: 0x0000, missing 7 packets 

que se espera. Desactive a perda de paquetes (ip netns exec P iptables -F) e intente aumentar a taxa de bits do xerador a 100 Mbps. O analizador informa unha morea de erros CC e uns 75 Mbps en lugar de 100. Estamos tentando descubrir quen é o culpable: o xerador non ten tempo ou o problema non está nel, para iso comezamos a xerar un número fixo de paquetes (700000 paquetes TS = 100000 paquetes IP):

# ifconfig veth0 | grep TX
       TX packets 151825460  bytes 205725459268 (191.5 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# tsp -I craft -c 700000 -P regulate -b 100000000 -P count -O ip -p 7 -e --local-port 6000 239.0.0.1:1234
* count: PID    0 (0x0000):    700,000 packets
# ifconfig veth0 | grep TX
        TX packets 151925460  bytes 205861259268 (191.7 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Como podes ver, xeráronse exactamente 100000 paquetes IP (151925460-151825460). Entón, imos descubrir o que está a suceder co analizador, para iso comprobamos co contador RX en veth1, é estrictamente igual ao contador TX en veth0, entón miramos o que ocorre a nivel de socket:

# ip netns exec P cat /proc/net/udp                                                                                                           
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops             
  133: 010000EF:04D2 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 72338 2 00000000e0a441df 24355 

Aquí podes ver o número de caídas = 24355. Nos paquetes TS, isto é 170485 ou 24.36% de 700000, polo que vemos que ese mesmo 25% da taxa de bits perdida son caídas no socket udp. As caídas nun socket UDP adoitan ocorrer debido á falta de búfer, mira o tamaño predeterminado do búfer do socket e o tamaño máximo do búfer do socket:

# sysctl net.core.rmem_default
net.core.rmem_default = 212992
# sysctl net.core.rmem_max
net.core.rmem_max = 212992

Así, se as aplicacións non solicitan explícitamente un tamaño de búfer, créanse sockets cun búfer de 208 KB, pero se solicitan máis, aínda non recibirán o solicitado. Dado que pode establecer o tamaño do búfer en tsp para a entrada IP (-buffer-size), non tocaremos o tamaño do zócalo predeterminado, senón que só definiremos o tamaño máximo do búfer e especificaremos o tamaño do búfer de forma explícita a través dos argumentos tsp:

sysctl net.core.rmem_max=8388608
ip netns exec P tsp --realtime -t -I ip 239.0.0.1:1234 -b 8388608 -P continuity -P bitrate_monitor -p 1 -t 1 -O drop

Con esta axuste do búfer do socket, agora a taxa de bits informada é duns 100 Mbps, non hai erros CC.

Segundo o consumo de CPU da propia aplicación tsp. En relación a un núcleo i5-4260U CPU a 1.40 GHz, a análise de fluxo de 10 Mbps requirirá un 3-4 % de CPU, 100 Mbps - 25 %, 200 Mbps - 46 %. Ao configurar o % de perda de paquetes, a carga da CPU practicamente non aumenta (pero pode diminuír).

En hardware máis produtivo, foi posible xerar e analizar fluxos de máis de 1 Gb/s sen ningún problema.

Probas en tarxetas de rede reais

Despois de probar nun par veth, cómpre tomar dous hosts ou dous portos dun host, conectar os portos entre si, iniciar o xerador nun e o analizador no segundo. Aquí non houbo sorpresas, pero de feito todo depende do ferro, canto máis débil, máis interesante será aquí.

Usando os datos recibidos polo sistema de monitorización (Zabbix)

tsp non ten ningunha API lexible pola máquina como SNMP ou similar. As mensaxes CC deben agregarse durante polo menos 1 segundo (cunha alta porcentaxe de perda de paquetes, pode haber centos/miles/decenas de miles por segundo, dependendo da taxa de bits).

Así, para gardar tanto información como debuxar gráficos de erros CC e taxa de bits e producir algún tipo de accidente, poden existir as seguintes opcións:

  1. Analiza e agrega (por CC) a saída de tsp, é dicir. convertelo á forma desexada.
  2. Remate a propia tsp e/ou os complementos do procesador bitrate_monitor e a continuidade para que o resultado se dea nunha forma lexible pola máquina adecuada para o sistema de monitorización.
  3. Escribe a túa solicitude enriba da biblioteca tsduck.

Obviamente, a opción 1 é a máis sinxela en termos de esforzo, especialmente tendo en conta que o propio tsduck está escrito nunha linguaxe de baixo nivel (según os estándares modernos) (C++)

Un simple prototipo de analizador bash + agregador mostrou que nun fluxo de 10 Mbps e unha perda de paquetes do 50 % (o peor dos casos), o proceso bash consumía 3-4 veces máis CPU que o propio proceso tsp. Este escenario é inaceptable. En realidade, unha peza deste prototipo a continuación

Fideos na parte superior

#!/usr/bin/env bash

missingPackets=0
ccErrorSeconds=0
regexMissPackets='^* (.+) - continuity:.*missing ([0-9]+) packets$'
missingPacketsTime=""

ip netns exec P tsp --realtime -t -I ip -b 8388608 "239.0.0.1:1234" -O drop -P bitrate_monitor -p 1 -t 1  -P continuity 2>&1 | 
while read i
do
    #line example:* 2019/12/28 23:41:14 - continuity: packet index: 6,078, PID: 0x0100, missing 5 packets
    #line example 2: * 2019/12/28 23:55:11 - bitrate_monitor: 2019/12/28 23:55:11, TS bitrate: 4,272,864 bits/s
    if [[ "$i" == *continuity:* ]] 
    then
        if [[ "$i" =~ $regexMissPackets ]]
        then
            missingPacketsTimeNew="${BASH_REMATCH[1]}" #timestamp (seconds)
            if [[ "$missingPacketsTime" != "$missingPacketsTimeNew" ]] #new second with CC error
            then
                ((ccErrorSeconds += 1))
            fi
            missingPacketsTime=$missingPacketsTimeNew
            packets=${BASH_REMATCH[2]} #TS missing packets
            ((missingPackets += packets))
        fi
    elif [[ "$i" == *bitrate_monitor:* ]]
    then
        : #...
    fi
done

Ademais de ser inaceptablemente lento, non hai fíos normais en bash, os traballos bash son procesos separados e tiven que escribir o valor de missingPackets unha vez por segundo no efecto secundario (ao recibir mensaxes de bitrate que chegan cada segundo). Como resultado, bash quedou só e decidiuse escribir un envoltorio (analizador + agregador) en golang. O consumo de CPU dun código golang similar é 4-5 veces menor que o propio proceso tsp. A aceleración do envoltorio debido á substitución de bash por golang resultou ser unhas 16 veces e, en xeral, o resultado é aceptable (a sobrecarga da CPU nun 25% no peor dos casos). Localízase o ficheiro fonte do golang aquí.

Executar envoltorio

Para iniciar o envoltorio, creouse o modelo de servizo máis sinxelo para systemd (aquí). Suponse que o propio wrapper está compilado nun ficheiro binario (vai a compilar tsduck-stat.go) situado en /opt/tsduck-stat/. Suponse que está a usar golang con soporte para reloxo monótono (>=1.9).

Para crear unha instancia do servizo, cómpre executar o comando systemctl enable [protexido por correo electrónico]:1234, despois executar con systemctl start [protexido por correo electrónico]: 1234.

Descubrimento de Zabbix

Para que zabbix poida descubrir servizos en execución, está feito xerador de listas de grupos (discovery.sh), no formato necesario para o descubrimento de Zabbix, suponse que está situado no mesmo lugar - en /opt/tsduck-stat. Para executar o descubrimento mediante zabbix-agent, cómpre engadir ficheiro .conf ao directorio de configuración de zabbix-agent para engadir o parámetro de usuario.

Modelo Zabbix

Modelo creado (tsduck_stat_template.xml) contén a regra de detección automática, prototipos de elementos, gráficos e activadores.

Lista de verificación breve (ben, que pasa se alguén decide usala)

  1. Asegúrese de que tsp non solta paquetes en condicións "ideais" (xerador e analizador están conectados directamente), se hai caídas, consulte o parágrafo 2 ou o texto do artigo sobre este asunto.
  2. Axuste o búfer máximo de socket (net.core.rmem_max=8388608).
  3. Compile tsduck-stat.go (vai a construír tsduck-stat.go).
  4. Coloque o modelo do servizo en /lib/systemd/system.
  5. Inicie os servizos con systemctl, comprobe que os contadores comezaron a aparecer (grep "" /dev/shm/tsduck-stat/*). O número de servizos segundo o número de fluxos de multidifusión. Aquí pode ter que crear unha ruta para o grupo de multidifusión, quizais desactivar rp_filter ou crear unha ruta para a ip fonte.
  6. Executa discovery.sh, asegúrate de que xera json.
  7. Engade a configuración do axente zabbix, reinicia o axente zabbix.
  8. Carga o modelo en zabbix, aplícao ao host que se está a supervisar e o axente zabbix está instalado, agarda uns 5 minutos, mira se hai novos elementos, gráficos e disparadores.

Resultado

Usando TSDuck para supervisar fluxos IP(TS).

Para a tarefa de detectar a perda de paquetes, é case suficiente, polo menos é mellor que non facer seguimento.

De feito, as "perdas" de CC poden ocorrer ao combinar fragmentos de vídeo (polo que sei, así se fan as insercións nos centros de televisión locais da Federación Rusa, é dicir, sen recalcular o contador CC), hai que lembralo. As solucións propietarias evitan parcialmente este problema detectando as etiquetas SCTE-35 (se as engade o xerador de fluxos).

En termos de vixilancia da calidade do transporte, hai unha falta de monitorización de jitter (IAT). Os equipos de televisión (sexan moduladores ou dispositivos finais) teñen requisitos para este parámetro e non sempre é posible inflar o jitbuffer ata o infinito. E o jitter pode flotar cando se usan equipos con grandes búfers en tránsito e a QoS non está configurada ou non está o suficientemente ben configurada para transmitir ese tráfico en tempo real.

Fonte: www.habr.com

Engadir un comentario