Към днешна дата съществуват готови (проприетарни) решения за мониторинг на IP(TS) потоци, например и , те разполагат с достатъчно богат набор от функции и обикновено подобни решения предлагат големите оператори, които работят с ТВ услуги. В тази статия е представено решение на базата на open source проект , предназначено за минимален контрол на IP(TS) потоци чрез брояча на продължителността (continuity counter) и битрейта. Един възможен вариант на приложение е контрол на загуба на пакети или на самия поток през нает L2 канал (който не може да се следи нормално, например чрез отчитане на загубите от опашките).
Много накратко за TSDuck
TSDuck е open source (лицензия 2-Clause BSD) софтуер (наблюдаващ набор от конзолни утилити и библиотека за разработка на собствени утилити или плъгини) за манипулация с TS потоци. Входът му може да работи с IP (multicast/unicast), http, hls, dvb тунери, демодулятор dektec dvb-asi, разполага с вътрешен генератор на TS поток и чете от файлове. Изходът може да бъде запис в файл, IP (multicast/unicast), hls, модулации dektec dvb-asi и HiDes, плеъри (mplayer, vlc, xine) и drop. Между входа и изхода могат да бъдат включени различни трафик процесори, например ремапиране на PID-ове, извършване на скремблиране/дескремблиране, анализ на CC броячи, изчисление на битрейта и други стандартни операции за TS потоци.
В тази статия като вход ще бъдат използвани IP потоци (multicast), с процесорите bitrate_monitor (името говори само за себе си) и continuity (анализ на CC броячи). Без особени проблеми можете да замените IP multicast с друг тип вход, поддържан от TSDuck.
Има налични TSDuck за повечето актуални ОС. За Debian такива не съществуват, но успяхме да компилираме без проблеми под Debian 8 и Debian 10.
По-долу се използва версия TSDuck 3.19-1520, с операционна система Linux (за подготовка на решението е използван Debian 10, за реална употреба — CentOS 7)
Подготовка на TSDuck и ОС
Преди да започнете да следите реалните потоци, е необходимо да се уверите, че TSDuck работи правилно и няма загуби на ниво мрежова карта или операционна система (сокет). Това е важно, за да се избегне догадките за причината на загубите – дали в мрежата или „вътре в сървъра“. Загубите на ниво мрежова карта могат да се проверят с командата ethtool -S ethX, а настройките се правят с ethtool (обикновено, трябва да се увеличи RX-бъфера (-G) и понякога да се изключат някои offloads (-K)). В качеството на обща препоръка можете да използвате отделен порт за приемане на анализирания трафик, ако имате такава възможност, това минимизира фалшивите срабатывания, свързани с факта, че загубата се е случила точно на порта на анализатора поради наличието на друг трафик. Ако такава възможност няма (използва се мини-компютър/NUC с един порт), то е много желателно да се настрои приоритет на анализирания трафик спрямо останалия трафик на устройството, към което е свързан анализатора. Относно виртуалните среди, тук трябва да бъдете внимателни и да можете да намирате загуби на пакети, започвайки от физическия порт и завършвайки с приложението вътре в виртуалната машина.
Генерация и прием на поток вътре в хоста
Като първа стъпка в подготовката, TSDuck ще генерира и приема трафик вътре в един хост, използвайки netns.
Подготвяме обкръжението:
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 #настройваме маршрут по подразбиране вътре в netns 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Обкръжението е готово. Стартираме анализатора на трафика:
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където „-p 1 -t 1“ означава, че трябва да изчислява битрейта всяка секунда и да извежда информация за битрейта всяка секунда
Стартираме генератора на трафик със скорост 10Мбит/с:
tsp -I craft
-P regulate -b 10000000
-O ip -p 7 -e --local-port 6000 239.0.0.1:1234където «-p 7 -e» означава, че трябва да се опаковат по 7 TS пакета в 1 IP пакет и да се прави стриктно (-e), т.е. винаги да се изчакват 7 TS пакета от последния процесор преди изпращането на образувания IP пакет.
Анализаторът започва да изведе очакваните съобщения:
* 2020/01/03 14:55:44 - bitrate_monitor: 2020/01/03 14:55:44, TS битрейт: 9,970,016 bits/s
* 2020/01/03 14:55:45 - bitrate_monitor: 2020/01/03 14:55:45, TS битрейт: 10,022,656 bits/s
* 2020/01/03 14:55:46 - bitrate_monitor: 2020/01/03 14:55:46, TS битрейт: 9,980,544 bits/sСега добавяме малко дропове:
ip netns exec P iptables -I INPUT -d 239.0.0.1 -m statistic --mode random --probability 0.001 -j DROPи се появяват съобщения от такъв тип:
* 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 което е очаквано. Изключваме загубата на пакети (ip netns exec P iptables -F) и опитваме да увеличим битрейта на генератора до 100Мбит/s. Анализаторът докладва множество CC-ошибки и около 75 Мбит/s вместо 100. Опитваме да разберем кой е виновен — дали генераторът не успява или проблема не е в него, за това стартираме генериране на фиксирано количество пакети (700000 TS пакета = 100000 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Както виждате, бяха генерирани точно 100000 IP пакета (151925460-151825460). Значи разглеждаме какво се случва с анализатора, за това сверяваме с брояча RX на veth1, той строго е равен на брояча TX на veth0, след това гледаме какво става на ниво сокет:
# 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 Тук е видимо количеството дропове = 24355. В TS пакетите това са 170485 или 24.36% от 700000, така че виждаме, че онези 25% загубен битрейт са дропове в udp сокета. Дроповете в UDP сокета обикновено възникват поради недостатъчен буфер, виждаме на какъв размер е буферът на сокета по подразбиране и максималният размер на буфера на сокета:
# sysctl net.core.rmem_default
net.core.rmem_default = 212992
# sysctl net.core.rmem_max
net.core.rmem_max = 212992Така че, ако приложенията не искат експлицитно размер на буфера, сокетите се създават с буфер от 208 Кб, но ако искат повече, пак няма да получат искания размер. Тъй като в tsp за IP вход може да бъде зададен размер на буфера (—buffer-size), то размера на сокета по подразбиране няма да променяме, а само ще зададем максималния размер на буфера на сокета и ще укажем размера на буфера експлицитно чрез аргументите 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С такова настройване на буфера на сокета, сега докладваният битрейт е приблизително 100Мбит/s, CC-ошибки няма.
По потребление на CPU от приложението tsp. За един ядро i5-4260U CPU @ 1.40GHz за анализ на поток от 10 Мбит/с ще са нужни 3-4% CPU, 100 Мбит/с — 25%, 200 Мбит/с — 46%. При задаване на % загуба на пакети, натоварването на CPU почти не нараства (но може да намалее).
На по-мощен хардуер без проблеми успяхме да генерираме и анализираме потоци над 1 Гб/с.
Тестване на реални мрежови карти
След тестовете на veth-пара, е нужно да вземете два хоста или два порта от един хост, да свържете портовете помежду им, на единия да стартирате генератор, а на другия - анализатор. Нямаше изненади, но всъщност всичко зависи от хардуера; колкото е по-слаб, толкова по-интересно ще бъде.
Използване на получените данни от системата за мониторинг (Zabbix)
tsp няма machine-readable API като SNMP или подобно. CC съобщенията трябва да се агрегатят поне на 1 секунда (при висок процент загуба на пакети, те могат да достигнат стотици/хиляди/десетки хиляди на секунда, в зависимост от битрейта).
Така че, за да запазите информацията и да нарисувате графики за CC грешки и битрейт, и да създадете някакви аварии, следните опции могат да се разгледат:
- Да парснете и агрегатирате (по CC) извода от tsp, т.е. да го преобразувате в необходимата форма.
- Да допълните самия tsp и/или процесорните плъгини bitrate_monitor и continuity, за да се получи резултат в machine-readable форма, подходяща за системата за мониторинг.
- Да напишете собствено приложение върху библиотеката tsduck.
Очевидно е, че от гледна точка на трудозатрат, вариант 1 е най-прост, особено предвид факта, че самият tsduck е написан на нискоуровневия (според съвременните стандарти) език (C++)
Простичък прототип на парсер+агрегатор на bash показа, че на поток от 10 Мбит/с и 50% загуба на пакети (най-лошия вариант), процесът на bash използва 3-4 пъти повече CPU, отколкото самият процес tsp. Тази развойна линия е неприемлива. Всъщност част от този прототип е по-долу.
Лапша на баша
#!/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Освен че работи неприемливо бавно, в bash липсват нормални нишки, bash jobs са независими процеси и беше необходимо да се записва веднъж в секунда стойността на missingPackets на страничния ефект (при получаване на съобщение за битрейта, които пристигат всяка секунда). В крайна сметка, bash беше оставен настрана и решихме да напишем обвивка (парсер+агрегатор) на golang. Консумацията на CPU на аналогичния код на golang е 4-5 пъти по-малка от самия процес tsp. Ускорението на обвивката благодарение на замяната на bash с golang е около 16 пъти и като цяло резултатът е приемлив (оверхед по CPU до 25% в най-лошия случай). Изходният файл на golang е .
Стартиране на обвивката
За стартиране на обвивката е направен най-простия шаблон на услуга за systemd (). Предполага се, че самата обвивка е компилирана в бинарен файл (go build tsduck-stat.go), разположен в /opt/tsduck-stat/. Предполага се, че се използва golang с поддръжка на монотонен часовник (>=1.9).
За да създадете инстанция на услугата, трябва да изпълните командата systemctl enable tsduck-stat@239.0.0.1:1234, след това да я стартирате с помощта на systemctl start tsduck-stat@239.0.0.1:1234.
Откритие от Zabbix
За да може zabbix да прави откритие на стартирани услуги, е направен (discovery.sh), в необходимия формат за Zabbix discovery, предполага се, че той е разположен там също — в /opt/tsduck-stat. За да стартирате откритие чрез zabbix-agent, трябва да добавите в директорията с конфигурации на zabbix-агента за добавяне на user параметър.
Шаблон Zabbix
(tsduck_stat_template.xml) съдържа правило за автоматично откритие, прототипи на елементи от данни, графики и тригери.
Кратък чеклист (вдруг случай някой реши да се възползва)
- Уверете се, че tsp не дропва пакети в „перфектни“ условия (генераторът и анализаторът са свързани директно), ако има дропове вижте т. 2 или текста на статията по този въпрос.
- Направете настройка на максималния буфер на сокета (net.core.rmem_max=8388608).
- Компилирайте tsduck-stat.go (go build tsduck-stat.go).
- Поставете шаблона на услугата в /lib/systemd/system.
- Стартирайте услугите с помощта на systemctl, проверете дали са започнали да се появяват с броячи (grep "" /dev/shm/tsduck-stat/*). Броят на услугите съответства на броя на multicast потоковете. Може да се наложи да създадете маршрут до multicast групата, може би да деактивирате rp_filter или да създадете маршрут до source ip.
- Стартирайте discovery.sh, уверете се, че генерира json.
- Поставете конфигурацията на zabbix-агента, перезапустете zabbix-агента.
- Качете шаблон в zabbix, прилагате го към хост, на който се извършва мониторинг и е инсталиран zabbix-agent, изчакайте около 5 минути, за да видите новите елементи на данните, графики и тригери.
Резултат

За задачата за откритие на загуби на пакети почти е достатъчно; в крайна сметка е по-добре отколкото липсата на мониторинг.
Наистина, CC-„загубите“ могат да възникнат при сглобяване на видеофрагменти (доколкото ми е известно, така се правят вмъквания в местните телевизионни центрове в Руската федерация, т.е. без преизчисляване на CC-счетчика), трябва да се помни. В собствените решения този проблем частично се избягва чрез откриване на маркировки SCTE-35 (ако те са добавени от генератора на потока).
От гледна точка на мониторинг на качеството на транспорта, липсва мониторинг на jitter (IAT), тъй като ТВ оборудването (било то модулиратори или крайни устройства) има изисквания за този параметър и не винаги е възможно да се увеличи jitbuffer до безкрайност. А jitter може да се колебае, когато на транзита се използва оборудване с големи буфери и QoS за предаване на такъв realtime трафик не е настроен или не е достатъчно добре настроен.
Източник: habr.com
