使用TSDuck監控IP(TS)流

今天,有現成的(專有的)解決方案用於監控 IP(TS) 流,例如 VB и iQ, 它們具有相當豐富的功能集,通常處理電視服務的大型運營商都有這樣的解決方案。 本文介紹基於一個開源項目的解決方案 鴨鴨,專為通過 CC(連續性計數器)計數器和比特率對 IP(TS)流進行最小控製而設計。 一個可能的應用是通過租用的 L2 通道控制數據包或整個流量的丟失(無法正常監控,例如,通過讀取隊列中的丟失計數器)。

非常簡單地介紹 TSDuck

TSDuck 是一個用於操作 TS 流的開源(2-Clause BSD 許可證)軟件(一組控制台實用程序和一個用於開發自定義實用程序或插件的庫)。 作為輸入,它可以與 IP(多播/單播)、http、hls、dvb 調諧器、dektec dvb-asi 解調器一起使用,有一個內部 TS 流生成器並從文件中讀取。 輸出可以寫入文件、IP(多播/單播)、hls、dektec dvb-asi 和 HiDes 調製器、播放器(mplayer、vlc、xine)和 drop。 輸入和輸出之間可以包含各種流量處理器,例如,PID 重映射、加擾/解擾、CC 計數器分析、比特率計算以及其他典型的 TS 流操作。

在本文中,IP 流(多播)將用作輸入,使用處理器 bitrate_monitor(從名稱中可以清楚地看出它是什麼)和連續性(CC 計數器的分析)。 您可以輕鬆地將 IP 多播替換為 TSDuck 支持的另一種輸入類型。

官方構建/包 適用於大多數當前操作系統的 TSDuck。 它們不適用於 Debian,但我們成功地在 debian 8 和 debian 10 下構建了它們,沒有任何問題。

接下來使用版本TSDuck 3.19-1520,操作系統為Linux(準備方案使用debian 10,實際使用CentOS 7)

準備 TSDuck 和操作系統

在監控真實流量之前,您需要確保 TSDuck 正常工作並且在網卡或 OS(套接字)級別沒有掉線。 這是必需的,以免以後猜測丟失發生的位置 - 在網絡上或“服務器內部”。 您可以使用 ethtool -S ethX 命令在網卡級別檢查丟包,調優是通過相同的 ethtool 完成的(通常,您需要增加 RX 緩衝區 (-G),有時需要禁用一些卸載 (-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 #настраиваем маршрут по умолчанию внутри 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

環境準備好了。 我們啟動流量分析器:

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”表示你需要每秒計算一次碼率並每秒顯示有關碼率的信息
我們以 10Mbps 的速度啟動流量生成器:

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),即在發送 IP 數據包之前,總是等待來自最後一個處理器的 7 個 TS 數據包。

分析器開始輸出預期的消息:

* 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

現在添加一些水滴:

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) 並嘗試將生成器比特率增加到 100Mbps。 分析器報告了一堆 CC 錯誤和大約 75 Mbps 而不是 100 Mbps。我們試圖找出誰應該受到指責 - 生成器沒有時間或問題不在其中,為此我們開始生成固定數量的數據包(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)。 所以讓我們弄清楚分析器發生了什麼,為此我們檢查 veth1 上的 RX 計數器,它嚴格等於 veth0 上的 TX 計數器,然後我們看看在套接字級別發生了什麼:

# 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 KB 緩衝區的套接字,但如果它們請求更多,它們仍然不會收到請求的內容。 由於您可以為 IP 輸入 (-buffer-size) 以 tsp 為單位設置緩衝區大小,因此我們不會觸及默認套接字大小,而只會設置最大套接字緩衝區大小並通過 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

通過調整套接字緩衝區,現在報告的比特率約為 100Mbps,沒有 CC 錯誤。

根據tsp應用本身的CPU消耗。 相對於一顆核心 i5-4260U CPU @ 1.40GHz,10Mbps 流量分析需要 3-4% CPU,100Mbps - 25%,200Mbps - 46%。 設置 % Packet Loss 時,CPU 的負載實際上不會增加(但可能會減少)。

在更高效的硬件上,可以毫無問題地生成和分析超過 1Gb/s 的流。

在真實網卡上測試

在對一個 veth 對進行測試後,你需要拿兩台主機或一台主機的兩個端口,將端口相互連接,在一個上啟動生成器,在第二個上啟動分析器。 這裡沒有驚喜,但實際上全靠鐵,越弱的這裡就越有趣。

使用監控系統(Zabbix)接收到的數據

tsp 沒有任何機器可讀的 API,如 SNMP 或類似的。 CC 消息必須聚合至少 1 秒(丟包率很高,每秒可能有數百/數千/數万,具體取決於比特率)。

因此,為了保存信息並繪製 CC 錯誤和比特率的圖表並製造某種事故,可能有以下選項:

  1. 解析並聚合(通過 CC)tsp 的輸出,即將其轉換為所需的形式。
  2. 完成 tsp 本身和/或處理器插件 bitrate_monitor 和連續性,以便以適合監控系統的機器可讀形式給出結果。
  3. 在 tsduck 庫之上編寫您的應用程序。

顯然,就人工成本而言,選項 1 是最簡單的,尤其是考慮到 tsduck 本身是用低級(按現代標準)語言(C++)編寫的

一個簡單的 bash 解析器 + 聚合器原型表明,在 10Mbps 流和 50% 數據包丟失(最壞情況)下,bash 進程消耗的 CPU 比 tsp 進程本身多 3-4 倍。 這種情況是不可接受的。 實際上是下面這個原型的一部分

麵條在上面

#!/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 作業是獨立的進程,而且我不得不每秒寫入一次 missingPackets 的值以防止副作用(當接收到每秒出現的比特率消息時)。 結果,bash 被擱置了,決定用 golang 寫一個包裝器(parser + aggregator)。 類似golang代碼的CPU消耗比tsp進程本身少4-5倍。 由於用 golang 替換 bash 而導致的包裝器加速大約是 16 倍,並且通常結果是可以接受的(在最壞的情況下 CPU 開銷為 25%)。 golang源文件所在 這裡.

運行包裝器

為了啟動包裝器,製作了最簡單的 systemd 服務模板(這裡). 包裝器本身應該被編譯成位於 /opt/tsduck-stat/ 中的二進製文件(go build tsduck-stat.go)。 假設您使用的是支持單調時鐘 (>=1.9) 的 golang。

要創建服務實例,需要運行 systemctl enable 命令 [電子郵件保護]:1234 然後用 systemctl start 運行 [電子郵件保護]:1234。

來自 Zabbix 的發現

為了讓zabbix能夠發現正在運行的服務,完成了 組列表生成器 (discovery.sh),以 Zabbix 發現所需的格式,假設它位於同一個地方 - 在 /opt/tsduck-stat 中。 要通過 zabbix-agent 運行發現,你需要添加 .conf 文件 到zabbix-agent配置目錄下添加user參數。

Zabbix模板

創建模板 (tsduck_stat_template.xml) 包含自動發現規則、項目原型、圖表和触發器。

簡要清單(好吧,如果有人決定使用它怎麼辦)

  1. 確保 tsp 在“理想”條件下(生成器和分析器直接連接)不會丟包,如果有丟包,請參閱第 2 段或有關此問題的文章正文。
  2. 調整最大套接字緩衝區 (net.core.rmem_max=8388608)。
  3. 編譯 tsduck-stat.go (go build tsduck-stat.go)。
  4. 將服務模板放在 /lib/systemd/system 中。
  5. 使用 systemctl 啟動服務,檢查計數器是否已開始出現 (grep "" /dev/shm/tsduck-stat/*)。 服務的數量由多播流的數量決定。 在這裡您可能需要創建到多播組的路由,可能禁用 rp_filter 或創建到源 ip 的路由。
  6. 運行 discovery.sh,確保它生成 json。
  7. 添加zabbix agent配置,重啟zabbix agent。
  8. 將模板上傳到zabbix,應用到被監控的主機上,安裝了zabbix-agent,等待5分鐘左右,看是否有新的item、graphs和trigger。

導致

使用TSDuck監控IP(TS)流

對於檢測丟包的任務來說,差不多就夠了,至少比沒有監控要好。

事實上,合併視頻片段時可能會發生 CC“丟失”(據我所知,這是俄羅斯聯邦當地電視中心的插入方式,即不重新計算 CC 計數器),必須記住這一點。 專有解決方案通過檢測 SCTE-35 標籤(如果由流生成器添加)來部分規避此問題。

在傳輸質量監控方面,缺乏抖動監控(IAT)。 電視設備(調製器或終端設備)對此參數有要求,並不總是可以將 jitbuffer 膨脹到無窮大。 當在傳輸過程中使用具有大緩衝區的設備並且 QoS 未配置或配置不夠好以傳輸此類實時流量時,抖動可能會浮動。

來源: www.habr.com

添加評論