Použití TSDuck ke sledování IP (TS) streamů

Dnes už existují hotová (proprietární) řešení například pro monitorování IP(TS) streamů VB и iQ, mají poměrně bohatou sadu funkcí a obvykle velcí operátoři zabývající se televizními službami taková řešení mají. Tento článek popisuje řešení založené na projektu s otevřeným zdrojovým kódem TSDuck, navržený pro minimální kontrolu IP(TS) toků pomocí CC (počítadla kontinuity) čítače a bitové rychlosti. Možnou aplikací je řízení ztráty paketů nebo celého toku pronajatým L2 kanálem (který nelze běžně sledovat např. čtením čítačů ztrát ve frontách).

Velmi stručně o TSDuck

TSDuck je open source (licence 2-Clause BSD) software (sada konzolových utilit a knihovna pro vývoj vlastních utilit nebo pluginů) pro manipulaci s TS streamy. Jako vstup umí pracovat s IP (multicast/unicast), http, hls, dvb tunery, demodulátorem dektec dvb-asi, nechybí interní generátor TS-streamu a čtení ze souborů. Výstupem může být zápis do souboru, IP (multicast/unicast), hls, modulátory dektec dvb-asi a HiDes, přehrávače (mplayer, vlc, xine) a drop. Mezi vstup a výstup mohou být zahrnuty různé provozní procesory, například přemapování PID, kódování / dekódování, analýza čítače CC, výpočet bitové rychlosti a další typické operace pro toky TS.

V tomto článku budou jako vstup použity IP streamy (multicast), procesory bitrate_monitor (z názvu je jasné, co to je) a kontinuita (analýza CC čítačů). IP multicast můžete snadno nahradit jiným typem vstupu podporovaným TSDuck.

Tam jsou oficiální sestavení/balíčky TSDuck pro většinu současných operačních systémů. Nejsou dostupné pro Debian, ale podařilo se nám je bez problémů postavit pod debian 8 a debian 10.

Dále je použita verze TSDuck 3.19-1520, jako OS Linux (pro přípravu řešení byl použit debian 10, pro reálné použití CentOS 7)

Příprava TSDuck a OS

Před sledováním skutečných toků se musíte ujistit, že TSDuck funguje správně a nedochází k žádným poklesům na úrovni síťové karty nebo OS (socket). To je nutné, aby se později nehádalo, kde došlo k poklesu - v síti nebo „uvnitř serveru“. Poklesy na úrovni síťové karty můžete zkontrolovat pomocí příkazu ethtool -S ethX, ladění se provádí stejným nástrojem ethtool (obvykle je třeba zvýšit vyrovnávací paměť RX (-G) a někdy zakázat některá snížení zátěže (-K)). Jako obecné doporučení lze doporučit použití samostatného portu pro příjem analyzovaného provozu, pokud je to možné, minimalizuje se tím falešná pozitivita spojená se skutečností, že k poklesu došlo právě na portu analyzátoru kvůli přítomnosti jiného provozu. Pokud to není možné (používá se minipočítač/NUC s jedním portem), je velmi žádoucí nastavit prioritu analyzovaného provozu ve vztahu ke zbytku na zařízení, ke kterému je analyzátor připojen. Pokud jde o virtuální prostředí, zde musíte být opatrní a být schopni najít dropety počínaje fyzickým portem a konče aplikací uvnitř virtuálního stroje.

Generování a příjem streamu uvnitř hostitele

Jako první krok v přípravě TSDuck budeme generovat a přijímat provoz v rámci jednoho hostitele pomocí netns.

Příprava prostředí:

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

Prostředí je připraveno. Spustíme analyzátor provozu:

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

kde "-p 1 -t 1" znamená, že musíte vypočítat bitrate každou sekundu a každou sekundu zobrazit informace o bitrate
Spustíme generátor provozu s rychlostí 10 Mbps:

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

kde "-p 7 -e" znamená, že je potřeba zabalit 7 TS paketů do 1 IP paketu a udělat to natvrdo (-e), tzn. před odesláním IP paketu vždy počkejte 7 TS paketů od posledního procesoru.

Analyzátor začne vydávat očekávané zprávy:

* 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

Nyní přidejte pár kapek:

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

a objeví se tyto zprávy:

* 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 

což se očekává. Zakažte ztrátu paketů (ip netns exec P iptables -F) a zkuste zvýšit bitovou rychlost generátoru na 100 Mbps. Analyzátor hlásí spoustu chyb CC a asi 75 Mbps místo 100. Snažíme se přijít na to, kdo za to může - generátor nemá čas nebo problém není v něm, proto začneme generovat pevný počet pakety (700000 100000 paketů TS = XNUMX XNUMX paketů 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

Jak vidíte, bylo vygenerováno přesně 100000 151925460 IP paketů (151825460-1). Pojďme tedy zjistit, co se děje s analyzátorem, zkontrolujeme to pomocí počítadla RX na veth0, je to přesně stejné jako počítadlo TX na vethXNUMX, pak se podíváme na to, co se stane na úrovni zásuvky:

# 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 

Zde vidíte počet poklesů = 24355. V TS paketech je to 170485 nebo 24.36 % ze 700000 25, takže vidíme, že stejných XNUMX % ztraceného bitrate jsou poklesy v udp socketu. K výpadkům v soketu UDP obvykle dochází kvůli nedostatku vyrovnávací paměti, podívejte se na výchozí velikost vyrovnávací paměti soketu a maximální velikost vyrovnávací paměti soketu:

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

Pokud tedy aplikace explicitně nepožadují velikost vyrovnávací paměti, jsou vytvořeny sokety s vyrovnávací pamětí 208 kB, ale pokud požadují více, stále nedostanou to, co bylo požadováno. Protože můžete nastavit velikost vyrovnávací paměti v tsp pro vstup IP (-buffer-size), nedotkneme se výchozí velikosti soketu, ale pouze nastavíme maximální velikost vyrovnávací paměti soketu a explicitně určíme velikost vyrovnávací paměti pomocí argumentů 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

S tímto vyladěním soketové vyrovnávací paměti je nyní hlášená přenosová rychlost asi 100 Mbps, nejsou žádné chyby CC.

Podle spotřeby CPU samotné aplikace tsp. V porovnání s jedním jádrem i5-4260U CPU @ 1.40 GHz bude analýza toku 10 Mb/s vyžadovat 3–4 % CPU, 100 Mb/s – 25 %, 200 Mb/s – 46 %. Při nastavení % Packet Loss se zátěž CPU prakticky nezvyšuje (ale může klesat).

Na produktivnějším hardwaru bylo možné bez problémů generovat a analyzovat streamy nad 1Gb/s.

Testování na skutečných síťových kartách

Po testování na páru veth musíte vzít dva hostitele nebo dva porty jednoho hostitele, propojit porty navzájem, spustit generátor na jednom a analyzátor na druhém. Tady se žádné překvapení nekonalo, ale vlastně všechno záleží na železe, čím slabší, tím to tady bude zajímavější.

Použití přijatých dat monitorovacím systémem (Zabbix)

tsp nemá žádné strojově čitelné API, jako je SNMP nebo podobné. Zprávy CC musí být agregovány po dobu alespoň 1 sekundy (při vysokém procentu ztráty paketů to mohou být stovky/tisíce/desetitisíce za sekundu, v závislosti na bitrate).

Aby bylo možné uložit jak informace, tak vykreslit grafy pro chyby CC a datový tok a způsobit nějaké nehody, mohou existovat následující možnosti:

  1. Analyzujte a agregujte (pomocí CC) výstup tsp, tj. převést do požadované podoby.
  2. Dokončete samotný tsp a/nebo moduly procesoru bitrate_monitor a kontinuitu tak, aby byl výsledek uveden ve strojově čitelné podobě vhodné pro monitorovací systém.
  3. Napište svou aplikaci nad knihovnu tsduck.

Je zřejmé, že možnost 1 je z hlediska úsilí nejjednodušší, zvláště vezmeme-li v úvahu, že samotný tsduck je napsán v jazyce nízké úrovně (podle moderních standardů) (C ++)

Jednoduchý prototyp bash analyzátoru + agregátoru ukázal, že při 10Mbps streamu a 50% ztrátě paketů (nejhorší případ) bash proces spotřeboval 3-4krát více CPU než samotný tsp proces. Tento scénář je nepřijatelný. Vlastně kousek tohoto prototypu níže

Nahoře nudle

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

Kromě toho, že je to nepřijatelně pomalé, v bash nejsou žádná normální vlákna, bash joby jsou samostatné procesy a hodnotu missingPackets jsem musel napsat jednou za sekundu na vedlejší efekt (při příjmu zpráv s bitratem, které přicházejí každou sekundu). Výsledkem bylo, že bash zůstal sám a bylo rozhodnuto napsat obal (parser + agregátor) v golangu. Spotřeba CPU podobného golang kódu je 4-5krát menší než samotný proces tsp. Zrychlení wrapperu díky nahrazení bashe golangem dopadlo asi 16x a celkově je výsledek přijatelný (režie CPU o 25% v nejhorším případě). Zdrojový soubor golang je umístěn zde.

Spustit obal

Pro spuštění wrapperu byla vytvořena nejjednodušší šablona služby pro systemd (zde). Samotný obal by měl být zkompilován do binárního souboru (go build tsduck-stat.go) umístěného v /opt/tsduck-stat/. Předpokládá se, že používáte golang s podporou monotónních hodin (>=1.9).

Chcete-li vytvořit instanci služby, musíte spustit příkaz systemctl enable [chráněno e-mailem]:1234 pak spusťte se startem systemctl [chráněno e-mailem]: 1234.

Objev ze Zabbix

Aby zabbix mohl objevit běžící služby, je hotovo generátor skupinových seznamů (discovery.sh), ve formátu požadovaném pro vyhledávání Zabbix, předpokládá se, že se nachází na stejném místě - v /opt/tsduck-stat. Chcete-li spustit zjišťování prostřednictvím zabbix-agenta, musíte přidat .conf soubor do konfiguračního adresáře zabbix-agent a přidejte parametr uživatele.

Šablona Zabbix

Vytvořená šablona (tsduck_stat_template.xml) obsahuje pravidlo autodiscover, prototypy položek, grafy a spouštěče.

Stručný kontrolní seznam (no, co když se ho někdo rozhodne použít)

  1. Ujistěte se, že tsp nezahazuje pakety za "ideálních" podmínek (generátor a analyzátor jsou připojeny přímo), pokud k poklesu dochází, viz odstavec 2 nebo text článku na toto téma.
  2. Proveďte ladění maximální vyrovnávací paměti soketu (net.core.rmem_max=8388608).
  3. Zkompilujte tsduck-stat.go (přejděte na sestavení tsduck-stat.go).
  4. Vložte šablonu služby do /lib/systemd/system.
  5. Spusťte služby pomocí systemctl, zkontrolujte, zda se začaly objevovat čítače (grep "" /dev/shm/tsduck-stat/*). Počet služeb podle počtu toků multicast. Zde možná budete muset vytvořit cestu ke skupině multicast, možná zakázat rp_filter nebo vytvořit cestu ke zdrojové ip.
  6. Spusťte discovery.sh a ujistěte se, že generuje json.
  7. Přidejte konfiguraci agenta zabbix, restartujte agenta zabbix.
  8. Nahrajte šablonu na zabbix, aplikujte ji na hostitele, který je monitorován a zabbix-agent je nainstalován, počkejte asi 5 minut a podívejte se, zda jsou nové položky, grafy a spouštěče.

Výsledek

Použití TSDuck ke sledování IP (TS) streamů

Pro úlohu detekce ztráty paketů to téměř stačí, alespoň je to lepší než žádný monitoring.

Při slučování fragmentů videa skutečně může dojít ke „ztrátám“ CC (pokud vím, takto se vkládání provádí v místních televizních centrech v Ruské federaci, tj. bez přepočítávání počítadla CC), na to je třeba pamatovat. Patentovaná řešení tento problém částečně obcházejí detekcí značek SCTE-35 (pokud jsou přidány generátorem proudu).

Z hlediska sledování kvality přepravy chybí sledování jitteru (IAT). Televizní zařízení (ať už se jedná o modulátory nebo koncová zařízení) má na tento parametr požadavky a ne vždy je možné jitbuffer nafouknout do nekonečna. A jitter může plavat, když se při přenosu používá zařízení s velkými vyrovnávací paměti a QoS není nakonfigurováno nebo není dostatečně dobře nakonfigurováno pro přenos takového provozu v reálném čase.

Zdroj: www.habr.com

Přidat komentář