Używanie TSDuck do monitorowania strumieni IP (TS).

Obecnie dostępne są gotowe (własne) rozwiązania np. do monitorowania strumieni IP(TS). VB и iQ, mają dość bogaty zestaw funkcji i zwykle takie rozwiązania mają duzi operatorzy zajmujący się usługami telewizyjnymi. W tym artykule opisano rozwiązanie oparte na projekcie open source TSDuck, zaprojektowany do minimalnej kontroli strumieni IP (TS) przez licznik CC (licznik ciągłości) i przepływność. Możliwym zastosowaniem jest kontrola utraty pakietów lub całego przepływu przez dzierżawiony kanał L2 (czego nie można normalnie monitorować, na przykład poprzez odczyt liczników strat w kolejkach).

Bardzo krótko o TSDuck

TSDuck to oprogramowanie typu open source (2-klauzulowa licencja BSD) (zestaw narzędzi konsoli i biblioteka do tworzenia niestandardowych narzędzi lub wtyczek) do manipulowania strumieniami TS. Jako wejście może współpracować z IP (multicast/unicast), http, hls, tunery dvb, demodulator dektec dvb-asi, jest wewnętrzny generator TS-stream i odczyt z plików. Wyjściem może być zapis do pliku, IP (multicast/unicast), modulatory hls, dektec dvb-asi i HiDes, playery (mplayer, vlc, xine) i drop. Pomiędzy wejściem a wyjściem można włączyć różne procesory ruchu, na przykład ponowne mapowanie PID, szyfrowanie / deszyfrowanie, analizę liczników CC, obliczanie przepływności i inne typowe operacje dla strumieni TS.

W tym artykule strumienie IP (multicast) zostaną wykorzystane jako dane wejściowe, używane są procesory bitrate_monitor (od nazwy wiadomo, co to jest) i ciągłość (analiza liczników CC). Możesz łatwo zastąpić multiemisję IP innym typem wejścia obsługiwanym przez TSDuck.

oficjalne kompilacje/pakiety TSDuck dla większości obecnych systemów operacyjnych. Nie są dostępne dla Debiana, ale udało nam się je zbudować pod debianem 8 i debianem 10 bez żadnych problemów.

Następnie wykorzystywana jest wersja TSDuck 3.19-1520, jako system operacyjny wykorzystywany jest Linux (do przygotowania rozwiązania wykorzystano debian 10, do rzeczywistego wykorzystania użyto CentOS 7)

Przygotowanie TSDuck i systemu operacyjnego

Przed monitorowaniem rzeczywistych przepływów należy upewnić się, że TSDuck działa poprawnie i nie ma spadków na poziomie karty sieciowej lub systemu operacyjnego (gniazda). Jest to wymagane, aby później nie zgadywać, gdzie nastąpiły spadki - w sieci lub „wewnątrz serwera”. Możesz sprawdzić spadki na poziomie karty sieciowej poleceniem ethtool -S ethX, strojenie odbywa się tym samym ethtoolem (zwykle trzeba zwiększyć bufor RX (-G) i czasami wyłączyć niektóre odciążenia (-K)). Ogólną rekomendacją jest używanie oddzielnego portu do odbierania analizowanego ruchu, jeśli to możliwe, minimalizuje to fałszywe alarmy związane z faktem, że spadek nastąpił dokładnie na porcie analizatora z powodu obecności innego ruchu. Jeśli nie jest to możliwe (wykorzystywany jest minikomputer/NUC z jednym portem), to wysoce pożądane jest ustawienie priorytetyzacji analizowanego ruchu w stosunku do reszty na urządzeniu, do którego podłączony jest analizator. Jeśli chodzi o środowiska wirtualne, tutaj musisz być ostrożny i być w stanie znaleźć porzucone pakiety, zaczynając od fizycznego portu, a kończąc na aplikacji wewnątrz maszyny wirtualnej.

Generowanie i odbiór strumienia wewnątrz hosta

Pierwszym krokiem w przygotowaniu TSDuck będzie generowanie i odbieranie ruchu w ramach jednego hosta za pomocą sieci.

Przygotowanie środowiska:

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

Środowisko jest gotowe. Uruchamiamy analizator ruchu:

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

gdzie „-p 1 -t 1” oznacza, że ​​musisz obliczać bitrate co sekundę i wyświetlać informacje o przepływności co sekundę
Uruchamiamy generator ruchu z prędkością 10Mbps:

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

gdzie „-p 7 -e” oznacza, że ​​musisz spakować 7 pakietów TS do 1 pakietu IP i zrobić to mocno (-e), tj. zawsze czekaj 7 pakietów TS z ostatniego procesora przed wysłaniem pakietu IP.

Analizator zaczyna generować oczekiwane komunikaty:

* 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

Teraz dodaj kilka kropli:

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

i pojawiają się takie komunikaty:

* 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 

czego się oczekuje. Wyłącz utratę pakietów (ip netns exec P iptables -F) i spróbuj zwiększyć bitrate generatora do 100Mbps. Analizator zgłasza masę błędów CC i około 75 Mb/s zamiast 100. Próbujemy dowiedzieć się, kto jest winny - generator nie ma czasu lub problem nie jest w nim, w tym celu zaczynamy generować ustaloną liczbę pakiety (700000 100000 pakietów TS = XNUMX XNUMX pakietów 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 widać, wygenerowano dokładnie 100000 151925460 pakietów IP (151825460-1). Zastanówmy się więc, co dzieje się z analizatorem, w tym celu sprawdzamy licznik RX na veth0, jest on dokładnie równy licznikowi TX na vethXNUMX, a następnie patrzymy, co dzieje się na poziomie gniazda:

# 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 

Tutaj możesz zobaczyć liczbę spadków = 24355. W pakietach TS jest to 170485 lub 24.36% z 700000, więc widzimy, że te same 25% utraconej przepływności to spadki w gnieździe udp. Spadki w gnieździe UDP zwykle występują z powodu braku bufora, spójrz na domyślny rozmiar bufora gniazda i maksymalny rozmiar bufora gniazda:

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

Tak więc, jeśli aplikacje nie żądają jawnie rozmiaru bufora, gniazda są tworzone z buforem o wielkości 208 KB, ale jeśli zażądają więcej, nadal nie otrzymają tego, o co prosili. Ponieważ możesz ustawić rozmiar bufora w tsp dla wejścia IP (-buffer-size), nie będziemy dotykać domyślnego rozmiaru gniazda, a jedynie ustawimy maksymalny rozmiar bufora gniazda i jawnie określimy rozmiar bufora za pomocą argumentów 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

Dzięki temu dostrojeniu bufora gniazda, teraz zgłoszona przepływność wynosi około 100 Mb/s, nie ma błędów CC.

Według zużycia procesora przez samą aplikację tsp. W stosunku do jednego rdzenia procesora i5-4260U @ 1.40 GHz, analiza przepływu 10 Mb/s będzie wymagać 3-4% procesora, 100 Mb/s – 25%, 200 Mb/s – 46%. Podczas ustawiania % utraty pakietów obciążenie procesora praktycznie nie wzrasta (ale może się zmniejszyć).

Na bardziej produktywnym sprzęcie można było bez problemu generować i analizować strumienie o przepustowości powyżej 1Gb/s.

Testowanie na rzeczywistych kartach sieciowych

Po przeprowadzeniu testów na parze veth należy wziąć dwa hosty lub dwa porty jednego hosta, połączyć porty ze sobą, na jednym uruchomić generator, a na drugim analizator. Tutaj niespodzianek nie było, ale tak naprawdę wszystko zależy od żelaza, im słabsze, tym ciekawiej tu będzie.

Wykorzystanie otrzymanych danych przez system monitoringu (Zabbix)

tsp nie ma żadnego interfejsu API do odczytu maszynowego, takiego jak SNMP lub podobny. Wiadomości CC muszą być agregowane przez co najmniej 1 sekundę (przy wysokim odsetku utraty pakietów mogą to być setki/tysiące/dziesiątki tysięcy na sekundę, w zależności od szybkości transmisji).

Tak więc, aby zapisać zarówno informacje, jak i narysować wykresy dla błędów CC i szybkości transmisji bitów oraz dokonać pewnego rodzaju wypadków, mogą istnieć następujące opcje:

  1. Analizuj i agreguj (przez CC) dane wyjściowe tsp, tj. przekonwertuj go do pożądanej postaci.
  2. Dokończ sam tsp i/lub wtyczki procesora bitrate_monitor i Continuity tak, aby wynik był podany w formie czytelnej maszynowo, odpowiedniej dla systemu monitoringu.
  3. Napisz swoją aplikację na górze biblioteki tsduck.

Oczywiście opcja 1 jest najłatwiejsza pod względem nakładu pracy, zwłaszcza biorąc pod uwagę, że sam tsduck jest napisany w języku niskiego poziomu (jak na współczesne standardy) (C++)

Prosty prototyp parsera + agregatora bash pokazał, że przy strumieniu 10 Mb/s i utracie pakietów 50% (w najgorszym przypadku) proces bash zużywał 3-4 razy więcej procesora niż sam proces tsp. Ten scenariusz jest nie do przyjęcia. Właściwie kawałek tego prototypu poniżej

Makaron na wierzchu

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

Oprócz tego, że jest niedopuszczalnie powolny, w bash nie ma normalnych wątków, zadania bash są oddzielnymi procesami, a ja musiałem zapisywać wartość brakujących pakietów raz na sekundę ze względu na efekt uboczny (podczas otrzymywania wiadomości o przepływności bitowej, które pojawiają się co sekundę). W rezultacie bash został sam i zdecydowano się napisać wrapper (parser + agregator) w golangu. Zużycie procesora przez podobny kod golanga jest 4-5 razy mniejsze niż sam proces tsp. Przyspieszenie wrappera dzięki zastąpieniu basha golangiem okazało się około 16-krotne i ogólnie wynik jest akceptowalny (obciążenie procesora o 25% w najgorszym przypadku). Zlokalizowany jest plik źródłowy golang tutaj.

Uruchom opakowanie

Aby uruchomić opakowanie, wykonano najprostszy szablon usługi dla systemd (tutaj). Samo opakowanie ma być skompilowane do pliku binarnego (go build tsduck-stat.go) znajdującego się w /opt/tsduck-stat/. Zakłada się, że używasz golanga z obsługą zegara monotonicznego (>=1.9).

Aby utworzyć instancję usługi, należy uruchomić komendę systemctl enable [email chroniony]:1234 następnie uruchom z systememctl start [email chroniony]: 1234.

Odkrycie z Zabbix

Aby zabbix mógł wykryć uruchomione usługi, jest to zrobione generator listy grup (discovery.sh), w formacie wymaganym do wykrywania Zabbix zakłada się, że znajduje się w tym samym miejscu - w /opt/tsduck-stat. Aby uruchomić wykrywanie przez zabbix-agent, musisz dodać plik .conf do katalogu konfiguracyjnego zabbix-agent, aby dodać parametr użytkownika.

Szablon Zabbixa

Utworzony szablon (tsduck_stat_template.xml) zawiera regułę automatycznego wykrywania, prototypy elementów, wykresy i wyzwalacze.

Krótka lista kontrolna (a co jeśli ktoś zdecyduje się z niej skorzystać)

  1. Upewnij się, że tsp nie upuszcza pakietów w „idealnych” warunkach (generator i analizator są połączone bezpośrednio), jeśli występują spadki, patrz paragraf 2 lub tekst artykułu na ten temat.
  2. Dostosuj maksymalny bufor gniazda (net.core.rmem_max=8388608).
  3. Skompiluj tsduck-stat.go (zbuduj tsduck-stat.go).
  4. Umieść szablon usługi w /lib/systemd/system.
  5. Uruchom usługi za pomocą systemctl, sprawdź, czy liczniki zaczęły się pojawiać (grep "" /dev/shm/tsduck-stat/*). Liczba usług przez liczbę strumieni multiemisji. Tutaj może być konieczne utworzenie trasy do grupy multiemisji, być może wyłączenie rp_filter lub utworzenie trasy do źródłowego adresu IP.
  6. Uruchom Discovery.sh, upewnij się, że generuje json.
  7. Dodaj konfigurację agenta zabbix, zrestartuj agenta zabbix.
  8. Prześlij szablon do zabbix, zastosuj go na monitorowanym hoście i zabbix-agent jest zainstalowany, poczekaj około 5 minut, sprawdź, czy są nowe elementy, wykresy i wyzwalacze.

Doświadcz mocnych i skutecznych rezultatów

Używanie TSDuck do monitorowania strumieni IP (TS).

Do zadania wykrywania utraty pakietów prawie wystarczy, a przynajmniej jest to lepsze niż brak monitorowania.

Rzeczywiście, „straty” CC mogą wystąpić podczas łączenia fragmentów wideo (o ile mi wiadomo, tak powstają wstawki w lokalnych centrach telewizyjnych w Federacji Rosyjskiej, tj. bez ponownego obliczania licznika CC), należy o tym pamiętać. Własne rozwiązania częściowo omijają ten problem, wykrywając etykiety SCTE-35 (jeśli zostały dodane przez generator strumienia).

W zakresie monitoringu jakości transportu brakuje monitoringu jittera (IAT). Sprzęt telewizyjny (czy to modulatory, czy urządzenia końcowe) ma wymagania co do tego parametru i nie zawsze da się nadmuchać jitbuffer do nieskończoności. Jitter może unosić się, gdy w tranzycie używany jest sprzęt z dużymi buforami, a QoS nie jest skonfigurowany lub skonfigurowany niewystarczająco dobrze, aby przesyłać taki ruch w czasie rzeczywistym.

Źródło: www.habr.com

Dodaj komentarz