Använda TSDuck för att övervaka IP(TS)-strömmar

Idag finns det färdiga (proprietära) lösningar för övervakning av till exempel IP(TS)-strömmar VB и iQ, de har en ganska rik uppsättning funktioner och vanligtvis har stora operatörer som sysslar med tv-tjänster sådana lösningar. Den här artikeln beskriver en lösning baserad på ett projekt med öppen källkod TSDuck, designad för minimal kontroll av IP(TS)-strömmar med CC(kontinuitetsräknare) och bithastighet. En möjlig tillämpning är att kontrollera förlusten av paket eller hela flödet genom en hyrd L2-kanal (som inte kan övervakas normalt, till exempel genom att läsa förlusträknare i köer).

Mycket kortfattat om TSDuck

TSDuck är en programvara med öppen källkod (2-klausul BSD-licens) (en uppsättning konsolverktyg och ett bibliotek för att utveckla anpassade verktyg eller plugins) för att manipulera TS-strömmar. Som ingång kan den fungera med IP (multicast/unicast), http, hls, dvb tuners, dektec dvb-asi demodulator, det finns en intern TS-stream generator och läsning från filer. Utdata kan vara att skriva till en fil, IP (multicast/unicast), hls, dektec dvb-asi och HiDes-modulatorer, spelare (mplayer, vlc, xine) och drop. Olika trafikprocessorer kan inkluderas mellan ingång och utdata, till exempel PID-ommappning, kryptering/avkodning, CC-räknaranalys, bithastighetsberäkning och andra typiska operationer för TS-strömmar.

I den här artikeln kommer IP-strömmar (multicast) att användas som ingång, processorerna bitrate_monitor (från namnet är det tydligt vad det är) och kontinuitet (analys av CC-räknare). Du kan enkelt ersätta IP multicast med en annan ingångstyp som stöds av TSDuck.

Det finns officiella byggen/paket TSDuck för de flesta nuvarande operativsystem. De är inte tillgängliga för Debian, men vi lyckades bygga dem under debian 8 och debian 10 utan problem.

Därefter används version TSDuck 3.19-1520, Linux används som operativsystem (debian 10 användes för att förbereda lösningen, CentOS 7 användes för verklig användning)

Förbereder TSDuck och OS

Innan du övervakar verkliga flöden måste du se till att TSDuck fungerar korrekt och att det inte finns några fall på nätverkskorts- eller OS-nivå (socket). Detta krävs för att inte senare gissa var fallen inträffade - på nätverket eller "inne i servern". Du kan kontrollera fall på nätverkskortsnivå med ethtool -S ethX-kommandot, inställningen görs av samma ethtool (vanligtvis måste du öka RX-bufferten (-G) och ibland inaktivera vissa avlastningar (-K)). Som en allmän rekommendation kan det rekommenderas att använda en separat port för att ta emot den analyserade trafiken, om möjligt, detta minimerar falska positiva resultat förknippade med det faktum att fallet inträffade exakt på analysatorns port på grund av närvaron av annan trafik. Om detta inte är möjligt (en minidator/NUC med en port används) så är det mycket önskvärt att sätta upp prioriteringen av den analyserade trafiken i förhållande till resten på enheten som analysatorn är ansluten till. Angående virtuella miljöer, här måste du vara försiktig och kunna hitta paketdroppar som börjar från en fysisk port och slutar med en applikation inuti en virtuell maskin.

Generering och mottagning av en ström inuti värden

Som ett första steg i att förbereda TSDuck kommer vi att generera och ta emot trafik inom en enda värd med hjälp av netns.

Förbereda miljön:

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

Miljön är redo. Vi startar trafikanalysatorn:

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

där "-p 1 -t 1" betyder att du behöver beräkna bithastigheten varje sekund och visa information om bithastigheten varje sekund
Vi startar trafikgeneratorn med en hastighet på 10 Mbps:

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

där "-p 7 -e" betyder att du behöver packa 7 TS-paket i 1 IP-paket och göra det hårt (-e), d.v.s. vänta alltid 7 TS-paket från den sista processorn innan du skickar ett IP-paket.

Analysatorn börjar mata ut de förväntade meddelandena:

* 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

Lägg nu till några droppar:

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

och meddelanden som detta visas:

* 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 

vilket förväntas. Inaktivera paketförlust (ip netns exec P iptables -F) och försök öka generatorns bithastighet till 100 Mbps. Analysatorn rapporterar ett gäng CC-fel och cirka 75 Mbps istället för 100. Vi försöker ta reda på vem som är skyldig - generatorn har inte tid eller problemet finns inte i den, för detta börjar vi generera ett fast antal paket (700000 100000 TS-paket = XNUMX XNUMX IP-paket):

# 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

Som du kan se genererades exakt 100000 151925460 IP-paket (151825460-1). Så låt oss ta reda på vad som händer med analysatorn, för detta kontrollerar vi med RX-räknaren på veth0, den är strikt lika med TX-räknaren på vethXNUMX, sedan tittar vi på vad som händer på sockelnivån:

# 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 

Här kan du se antalet droppar = 24355. I TS-paket är detta 170485 eller 24.36% av 700000, så vi ser att samma 25% av den förlorade bithastigheten är droppar i udp-socket. Fall i en UDP-socket uppstår vanligtvis på grund av brist på buffert, titta på standardsockets buffertstorlek och den maximala socketbuffertstorleken:

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

Således, om applikationer inte uttryckligen begär en buffertstorlek, skapas sockets med en buffert på 208 KB, men om de begär mer kommer de fortfarande inte att få det som efterfrågades. Eftersom du kan ställa in buffertstorleken i tsp för IP-ingången (-buffert-storlek), kommer vi inte att röra standardsocketstorleken, utan endast ställa in den maximala sockets buffertstorlek och specificera buffertstorleken explicit genom 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

Med denna inställning av socketbufferten, nu den rapporterade bithastigheten är cirka 100 Mbps, finns det inga CC-fel.

Enligt processorförbrukningen för själva tsp-applikationen. I förhållande till en kärna i5-4260U CPU @ 1.40 GHz, 10 Mbps flödesanalys kommer att kräva 3-4% CPU, 100 Mbps - 25%, 200 Mbps - 46%. När du ställer in % Packet Loss ökar belastningen på CPU:n praktiskt taget inte (men kan minska).

På mer produktiv hårdvara var det möjligt att generera och analysera strömmar på mer än 1Gb/s utan problem.

Testar på riktiga nätverkskort

Efter att ha testat på ett veth-par måste du ta två värdar eller två portar på en värd, ansluta portarna till varandra, starta generatorn på den ena och analysatorn på den andra. Det var inga överraskningar här, men i själva verket beror allt på järnet, ju svagare, desto mer intressant blir det här.

Använda mottagna data av övervakningssystemet (Zabbix)

tsp har inget maskinläsbart API som SNMP eller liknande. CC-meddelanden måste aggregeras i minst 1 sekund (med en hög procentandel av paketförlust kan det finnas hundratals/tusentals/tiotusentals per sekund, beroende på bithastigheten).

För att spara både information och rita grafer för CC-fel och bithastighet och göra någon form av olyckor kan det alltså finnas följande alternativ:

  1. Analysera och aggregera (med CC) produktionen av tsp, dvs. konvertera den till önskad form.
  2. Slutför tsp själv och/eller processorplugin bitrate_monitor och kontinuitet så att resultatet ges i en maskinläsbar form lämplig för övervakningssystemet.
  3. Skriv din ansökan ovanpå tsduck-biblioteket.

Uppenbarligen är alternativ 1 det enklaste när det gäller ansträngning, särskilt med tanke på att tsduck i sig är skrivet på ett lågnivåspråk (enligt moderna standarder) (C ++)

En enkel prototyp för bash-parser+aggregator visade att på en ström på 10 Mbps och 50 % paketförlust (i värsta fall) förbrukade bash-processen 3-4 gånger mer CPU än själva tsp-processen. Detta scenario är oacceptabelt. Egentligen en del av denna prototyp nedan

Nudlar på toppen

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

Förutom att det är oacceptabelt långsamt finns det inga normala trådar i bash, bash-jobb är separata processer, och jag var tvungen att skriva värdet av missingPackets en gång i sekunden på bieffekten (när jag tar emot bithastighetsmeddelanden som kommer varje sekund). Som ett resultat lämnades bash ifred och det beslutades att skriva ett omslag (parser + aggregator) i golang. CPU-förbrukningen av liknande golang-kod är 4-5 gånger mindre än själva tsp-processen. Hastigheten på omslaget på grund av att bash ersatts med golang visade sig vara cirka 16 gånger och i allmänhet är resultatet acceptabelt (CPU-overhead med 25% i värsta fall). Golang-källfilen finns här.

Kör omslag

För att starta omslaget gjordes den enklaste servicemallen för systemd (här). Själva omslaget är tänkt att vara kompilerat till en binär fil (go build tsduck-stat.go) som finns i /opt/tsduck-stat/. Det antas att du använder golang med stöd för monoton klocka (>=1.9).

För att skapa en instans av tjänsten måste du köra kommandot systemctl enable [e-postskyddad]:1234 kör sedan med systemctl start [e-postskyddad]: 1234.

Upptäckt från Zabbix

För att zabbix ska kunna upptäcka löpande tjänster görs det grupplistgenerator (discovery.sh), i det format som krävs för Zabbix-upptäckt, antas det att det finns på samma plats - i /opt/tsduck-stat. För att köra upptäckt via zabbix-agent måste du lägga till .conf-fil till zabbix-agents konfigurationskatalog för att lägga till användarparametern.

Zabbix mall

Skapat mall (tsduck_stat_template.xml) innehåller autodiscover-regeln, objektprototyper, grafer och triggers.

Kort checklista (tja, tänk om någon bestämmer sig för att använda den)

  1. Se till att tsp inte tappar paket under "ideala" förhållanden (generator och analysator är anslutna direkt), om det finns droppar, se punkt 2 eller artikeltexten om denna fråga.
  2. Ställ in den maximala sockelbufferten (net.core.rmem_max=8388608).
  3. Kompilera tsduck-stat.go (bygg tsduck-stat.go).
  4. Lägg tjänstmallen i /lib/systemd/system.
  5. Starta tjänster med systemctl, kontrollera att räknare har börjat dyka upp (grep "" /dev/shm/tsduck-stat/*). Antalet tjänster efter antalet multicastströmmar. Här kan du behöva skapa en rutt till multicast-gruppen, kanske inaktivera rp_filter eller skapa en rutt till käll-ip.
  6. Kör discovery.sh, se till att det genererar json.
  7. Lägg till zabbix agent config, starta om zabbix agent.
  8. Ladda upp mallen till zabbix, applicera den på värden som övervakas och zabbix-agenten är installerad, vänta ca 5 minuter, se om det finns nya objekt, grafer och triggers.

Resultat

Använda TSDuck för att övervaka IP(TS)-strömmar

För uppgiften att upptäcka paketförlust räcker det nästan, åtminstone är det bättre än ingen övervakning.

Faktum är att CC-"förluster" kan uppstå vid sammanslagning av videofragment (så vitt jag vet är det så här insatser görs på lokala TV-center i Ryska federationen, d.v.s. utan att räkna om CC-räknaren), detta måste komma ihåg. Proprietära lösningar kringgår delvis detta problem genom att detektera SCTE-35-etiketter (om de läggs till av strömgeneratorn).

När det gäller övervakning av transportkvalitet saknas jitterövervakning (IAT). TV-utrustning (vare sig det är modulatorer eller slutenheter) har krav på denna parameter och det är inte alltid möjligt att blåsa upp jitbuffern till oändligheten. Och jitter kan flyta när utrustning med stora buffertar används i transit och QoS inte är konfigurerat eller inte tillräckligt välkonfigurerat för att överföra sådan realtidstrafik.

Källa: will.com

Lägg en kommentar