TSDuck gebruiken om IP(TS)-stromen te monitoren

Tegenwoordig bestaan ​​er kant-en-klare (eigen) oplossingen voor het monitoren van bijvoorbeeld IP(TS)-stromen VB и iQhebben ze een vrij rijke reeks functies en doorgaans hebben grote exploitanten die zich bezighouden met tv-diensten vergelijkbare oplossingen. Dit artikel beschrijft een oplossing op basis van een open source-project TSDuck, ontworpen voor minimale controle van IP(TS)-stromen met behulp van de CC-teller (continuity counter) en bitrate. Een mogelijke toepassing is het monitoren van het verlies van pakketten of de gehele stroom via een gehuurd L2-kanaal (dat niet normaal kan worden gemonitord, bijvoorbeeld door verliestellers in wachtrijen te lezen).

Heel kort over TSDuck

TSDuck is open source (BSD-licentie met twee clausules) software (een set consolehulpprogramma's en een bibliotheek voor het ontwikkelen van uw eigen hulpprogramma's of plug-ins) voor het manipuleren van TS-streams. Als invoer kan het werken met IP (multicast/unicast), http, hls, dvb-tuners, dektec dvb-asi demodulator, er is een interne TS-streamgenerator en het lezen van bestanden. De uitvoer kan bestaan ​​uit opnemen naar een bestand, IP (multicast/unicast), hls, dektec dvb-asi en HiDes modulators, spelers (mplayer, vlc, xine) en drop. Tussen de invoer en uitvoer kunt u verschillende verkeersprocessors inschakelen, bijvoorbeeld het opnieuw toewijzen van PID's, het doen van scrambling/descrambling, het analyseren van CC-counters, het berekenen van de bitrate en andere bewerkingen die typisch zijn voor TS-streams.

In dit artikel zullen IP-streams (multicast) als invoer worden gebruikt, zullen bitrate_monitor-processors (vanaf de naam is duidelijk wat dit is) en continuïteits- (CC counter-analyse) processors worden gebruikt. Zonder problemen kunt u IP-multicast vervangen door een ander invoertype dat door TSDuck wordt ondersteund.

Er zijn officiële builds/pakketten TSDuck voor de meeste huidige besturingssystemen. Er zijn er geen voor Debian, maar we zijn erin geslaagd ze zonder problemen voor Debian 8 en Debian 10 te compileren.

Vervolgens wordt TSDuck versie 3.19-1520 gebruikt, Linux als besturingssysteem (debian 10 werd gebruikt om de oplossing voor te bereiden, CentOS 7 werd gebruikt voor feitelijk gebruik)

TSDuck en besturingssysteem voorbereiden

Voordat u echte stromen monitort, moet u ervoor zorgen dat TSDuck correct werkt en dat er geen druppels optreden op het niveau van de netwerkkaart of het besturingssysteem (socket). Dit is nodig zodat u later niet hoeft te raden waar de drops hebben plaatsgevonden: op het netwerk of ‘binnen de server’. Je kunt drops op netwerkkaartniveau controleren met het commando ethtool -S ethX, het afstemmen gebeurt door dezelfde ethtool (meestal moet je de RX-buffer vergroten (-G) en soms enkele offloads uitschakelen (-K)). Als algemene aanbeveling is het raadzaam om een ​​aparte poort te gebruiken om het geanalyseerde verkeer te ontvangen. Indien mogelijk minimaliseert dit valse positieven vanwege het feit dat de daling tegelijkertijd op de analysatorpoort plaatsvond vanwege de aanwezigheid van ander verkeer. Als dit niet mogelijk is (u gebruikt een minicomputer/NUC met één poort), dan is het zeer raadzaam om de prioriteit van het geanalyseerde verkeer ten opzichte van de rest te configureren op het apparaat waarop de analysator is aangesloten. Wat virtuele omgevingen betreft, moet u hier voorzichtig zijn en pakketdroppings kunnen vinden, beginnend bij de fysieke poort en eindigend met de applicatie in de virtuele machine.

Een stream genereren en ontvangen binnen de host

Als eerste stap bij het voorbereiden van TSDuck zullen we verkeer binnen één host genereren en ontvangen met behulp van netns.

De omgeving voorbereiden:

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

De omgeving is er klaar voor. Start de verkeersanalysator:

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

waarbij “-p 1 -t 1” betekent dat u de bitrate elke seconde moet berekenen en elke seconde informatie over de bitrate moet weergeven
We lanceren een verkeersgenerator met een snelheid van 10 Mbit/s:

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

waarbij “-p 7 -e” betekent dat je 7 TS-pakketten in 1 IP-pakket moet verpakken en het hard moet doen (-e), d.w.z. wacht altijd op 7 TS-pakketten van de laatste processor voordat u de vorming van een IP-pakket verzendt.

De analysator begint de verwachte berichten weer te geven:

* 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

Laten we nu wat druppels toevoegen:

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

en er verschijnen berichten als deze:

* 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 

wat wordt verwacht. We schakelen pakketverlies uit (ip netns exec P iptables -F) en proberen de bitsnelheid van de generator te verhogen naar 100 Mbit/s. De analysator rapporteert een aantal CC-fouten en ongeveer 75 Mbit/s in plaats van 100. We proberen erachter te komen wie de schuldige is - de generator houdt het niet bij of het probleem zit er niet in. Om dit te doen, beginnen we met het genereren van een vast aantal pakketten (700000 TS-pakketten = 100000 IP-pakketten):

# 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

Zoals u kunt zien, zijn er precies 100000 IP-pakketten gegenereerd (151925460-151825460). Dus we zoeken uit wat er met de analysator gebeurt, om dit te doen controleren we met de RX-teller op veth1, deze is strikt gelijk aan de TX-teller op veth0, en dan kijken we naar wat er gebeurt op socketniveau:

# 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 

Hier kun je het aantal drops = 24355 zien. In TS-pakketten is dit 170485 of 24.36% van 700000, dus we zien dat dezelfde 25% van de verloren bitrate drops in de UDP-socket zijn. Druppels op een UDP-socket treden meestal op vanwege een gebrek aan buffer. Laten we eens kijken wat de standaard socketbuffergrootte en de maximale socketbuffergrootte zijn:

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

Als toepassingen dus niet expliciet om de buffergrootte vragen, worden er sockets gemaakt met een buffer van 208 KB, maar als ze meer vragen, ontvangen ze nog steeds niet wat ze hebben gevraagd. Omdat je in tsp de buffergrootte voor IP-invoer (--buffer-size) kunt instellen, zullen we de standaard socketgrootte niet aanraken, maar alleen de maximale socketbuffergrootte instellen en de buffergrootte expliciet specificeren via de tsp-argumenten:

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

Met deze afstemming van de socketbuffer bedraagt ​​de gerapporteerde bitsnelheid nu ongeveer 100 Mbps, er zijn geen CC-fouten.

Gebaseerd op CPU-verbruik door de TSP-applicatie zelf. Met betrekking tot één core i5-4260U CPU op 1.40 GHz is voor het analyseren van een stroom van 10 Mbit/s 3-4% van de CPU nodig, 100 Mbit/s - 25%, 200 Mbit/s - 46%. Bij het instellen van % pakketverlies neemt de CPU-belasting praktisch niet toe (maar kan wel afnemen).

Op productievere hardware was het mogelijk om zonder problemen streams van meer dan 1Gb/s te genereren en te analyseren.

Testen op echte netwerkkaarten

Na het testen op een veth-paar moet u twee hosts of twee poorten van één host nemen, de poorten met elkaar verbinden, de generator op de ene laten draaien en de analysator op de tweede. Er waren hier geen verrassingen, maar in feite hangt het allemaal af van de hardware: hoe zwakker het is, hoe interessanter het hier zal zijn.

Gebruik van de ontvangen gegevens door het monitoringsysteem (Zabbix)

tsp heeft geen machinaal leesbare API zoals SNMP of iets dergelijks. CC-berichten moeten minimaal 1 seconde per keer worden samengevoegd (bij een hoog percentage pakketverlies kunnen dit er honderden/duizenden/tienduizenden per seconde zijn, afhankelijk van de bitsnelheid).

Om dus informatie op te slaan en grafieken te tekenen voor CC-fouten en bitrate en nog meer ongelukken te veroorzaken, kunnen er de volgende opties zijn:

  1. Parseer en aggregeer (door CC) de tsp-uitvoer, d.w.z. transformeren in de gewenste vorm.
  2. Voeg de tsp zelf en/of de plug-ins bitrate_monitor en continuïteitsprocessor toe, zodat het resultaat wordt uitgevoerd in een machineleesbare vorm die geschikt is voor het monitoringsysteem.
  3. Schrijf uw aanvraag bovenaan de tsduck-bibliotheek.

Het is duidelijk dat optie 1, in termen van arbeidskosten, de eenvoudigste is, vooral gezien het feit dat tsduck zelf is geschreven in een taal op laag niveau (naar moderne normen) (C++).

Een eenvoudig prototype van een parser + aggregator in bash toonde aan dat bij een stroom van 10 Mbit/s en 50% pakketverlies (in het slechtste geval) het bash-proces 3-4 keer meer CPU verbruikte dan het tsp-proces zelf. Dit scenario is onaanvaardbaar. Eigenlijk staat een stukje van dit prototype hieronder

Noedels op basha

#!/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

Naast het feit dat dit onaanvaardbaar langzaam werkt, zijn er geen normale threads in bash, zijn bash-taken onafhankelijke processen en moest ik de ontbrekendePackets-waarde één keer per seconde schrijven als bijwerking (bij het ontvangen van bitrate-berichten die elke seconde komen). Als gevolg hiervan werd bash met rust gelaten en werd besloten een wrapper (parser + aggregator) in golang te schrijven. Het CPU-verbruik van vergelijkbare code in Golang is 4-5 keer minder dan het tsp-proces zelf. De versnelling van de wrapper door bash te vervangen door golang was ongeveer 16 keer en over het geheel genomen is het resultaat acceptabel (CPU-overhead met 25% in het ergste geval). Het Golang-bronbestand bevindt zich hier.

Het lanceren van de verpakking

Om de wrapper te lanceren, is een eenvoudig servicesjabloon voor systemd gemaakt (hier). Er wordt aangenomen dat de wrapper zelf is gecompileerd in een binair bestand (go build tsduck-stat.go), gelegen in /opt/tsduck-stat/. Er wordt aangenomen dat golang wordt gebruikt met monotone klokondersteuning (>=1.9).

Om een ​​service-instantie te maken, moet u de opdracht systemctl enable uitvoeren [e-mail beveiligd]:1234, voer het vervolgens uit met systemctl start [e-mail beveiligd]: 1234.

Ontdekking van Zabbix

Zodat zabbix een ontdekking kan doen van lopende services, groepslijstgenerator (discovery.sh), in het formaat dat vereist is voor Zabbix-detectie, wordt aangenomen dat het zich op dezelfde plaats bevindt - in /opt/tsduck-stat. Om detectie via zabbix-agent uit te voeren, moet u toevoegen .conf-bestand naar de map met zabbix-agent-configuraties om een ​​gebruikersparameter toe te voegen.

Zabbix-sjabloon

Sjabloon gemaakt (tsduck_stat_template.xml) bevat de autodiscovery-regel, het element, de grafiek en de trigger-prototypes.

Een korte checklist (wat als iemand besluit deze te gebruiken)

  1. Zorg ervoor dat tsp onder “ideale” omstandigheden geen pakketten dropt (de generator en analysator zijn direct met elkaar verbonden), als er drops zijn, zie dan punt 2 of de tekst van het artikel over dit onderwerp.
  2. Stem de maximale socketbuffer af (net.core.rmem_max=8388608).
  3. Compileer tsduck-stat.go (ga tsduck-stat.go bouwen).
  4. Plaats de servicesjabloon in /lib/systemd/system.
  5. Start services met systemctl, controleer of tellers verschijnen (grep "" /dev/shm/tsduck-stat/*). Aantal services op basis van het aantal multicaststreams. Hier moet u mogelijk een route naar de multicastgroep maken, misschien rp_filter uitschakelen of een route naar het bron-IP maken.
  6. Voer Discovery.sh uit en zorg ervoor dat json wordt gegenereerd.
  7. Plaats de zabbix agent-configuratie, start de zabbix-agent opnieuw.
  8. Upload de sjabloon naar zabbix, pas deze toe op de host waarop monitoring wordt uitgevoerd en zabbix-agent is geïnstalleerd, wacht ongeveer 5 minuten en zie dat er nieuwe data-elementen, grafieken en triggers zijn verschenen.

Resultaat

TSDuck gebruiken om IP(TS)-stromen te monitoren

Voor het identificeren van pakketverlies is dit bijna voldoende, in ieder geval beter dan geen monitoring.

In feite kunnen CC-"verliezen" optreden bij het splitsen van videofragmenten (voor zover ik weet, zo worden invoegingen gemaakt bij lokale televisiecentra in de Russische Federatie, d.w.z. zonder de CC-teller opnieuw te berekenen), dit moet onthouden worden. In propriëtaire oplossingen wordt dit probleem gedeeltelijk omzeild door SCTE-35-tags te detecteren (als deze door de streamgenerator worden toegevoegd).

Vanuit het oogpunt van monitoring van de transportkwaliteit is jittermonitoring (IAT) niet voldoende, omdat TV-apparatuur (of het nu modulatoren of eindapparaten zijn) stelt eisen aan deze parameter en het is niet altijd mogelijk om de jitbuffer voor onbepaalde tijd op te blazen. En jitter kan zweven wanneer transit apparatuur met grote buffers gebruikt en QoS niet of niet goed genoeg is geconfigureerd om dergelijk realtime verkeer te verzenden.

Bron: www.habr.com

Voeg een reactie