Sử dụng TSDuck để giám sát luồng IP(TS)

Ngày nay, có các giải pháp làm sẵn (độc quyền) để giám sát các luồng IP(TS), chẳng hạn như VB и iQ, chúng có một bộ chức năng khá phong phú và thường các nhà khai thác lớn kinh doanh dịch vụ TV đều có những giải pháp như vậy. Bài viết này mô tả một giải pháp dựa trên một dự án nguồn mở TSDuck, được thiết kế để kiểm soát tối thiểu các luồng IP(TS) bằng bộ đếm CC (bộ đếm liên tục) và tốc độ bit. Một ứng dụng khả thi là kiểm soát việc mất gói hoặc toàn bộ luồng thông qua kênh L2 được thuê (ví dụ: không thể giám sát bình thường bằng cách đọc bộ đếm tổn thất trong hàng đợi).

Rất ngắn gọn về TSDuck

TSDuck là một phần mềm nguồn mở (giấy phép BSD 2 điều khoản) (một bộ tiện ích bảng điều khiển và thư viện để phát triển các tiện ích hoặc plugin tùy chỉnh) để thao tác các luồng TS. Là một đầu vào, nó có thể hoạt động với IP (multicast/unicast), http, hls, bộ điều chỉnh dvb, bộ giải mã dektec dvb-asi, có một bộ tạo luồng TS nội bộ và đọc từ các tệp. Đầu ra có thể được ghi vào một tệp, IP (multicast/unicast), hls, dektec dvb-asi và bộ điều biến HiDes, trình phát (mplayer, vlc, xine) và drop. Bạn có thể kích hoạt nhiều bộ xử lý lưu lượng khác nhau giữa đầu vào và đầu ra, ví dụ: ánh xạ lại PID, xáo trộn/giải xáo trộn, phân tích bộ đếm CC, tính toán tốc độ bit và các hoạt động điển hình khác cho luồng TS.

Trong bài viết này, các luồng IP (multicast) sẽ được sử dụng làm đầu vào, bộ xử lý bitrate_monitor (từ tên đã rõ nó là gì) và tính liên tục (phân tích bộ đếm CC) sẽ được sử dụng. Bạn có thể dễ dàng thay thế IP multicast bằng loại đầu vào khác được TSDuck hỗ trợ.

bản dựng/gói chính thức TSDuck cho hầu hết các hệ điều hành hiện nay. Chúng không có sẵn cho Debian, nhưng chúng tôi đã cố gắng xây dựng chúng theo debian 8 và debian 10 mà không gặp vấn đề gì.

Tiếp theo, phiên bản TSDuck 3.19-1520 được sử dụng, Linux được sử dụng làm HĐH (debian 10 được sử dụng để chuẩn bị giải pháp, CentOS 7 được sử dụng để sử dụng thực tế)

Chuẩn bị TSDuck và hệ điều hành

Trước khi theo dõi các luồng thực, bạn cần đảm bảo rằng TSDuck hoạt động chính xác và không có hiện tượng rớt card mạng hoặc hệ điều hành (socket). Điều này là bắt buộc để sau này không đoán được nơi xảy ra sự cố rớt - trên mạng hoặc “bên trong máy chủ”. Bạn có thể kiểm tra mức sụt giảm ở cấp card mạng bằng lệnh ethtool -S ethX, việc điều chỉnh được thực hiện bởi cùng một ethtool (thông thường, bạn cần tăng bộ đệm RX (-G) và đôi khi vô hiệu hóa một số giảm tải (-K)). Theo khuyến nghị chung, bạn nên sử dụng một cổng riêng để nhận lưu lượng được phân tích, nếu có thể, điều này sẽ giảm thiểu các kết quả dương tính giả liên quan đến thực tế là sự sụt giảm xảy ra chính xác trên cổng của máy phân tích do sự hiện diện của lưu lượng truy cập khác. Nếu điều này là không thể (sử dụng máy tính mini/NUC có một cổng), thì bạn nên thiết lập mức độ ưu tiên của lưu lượng được phân tích liên quan đến phần còn lại trên thiết bị mà máy phân tích được kết nối. Về môi trường ảo, ở đây bạn cần phải cẩn thận và có thể tìm thấy các gói bị rớt bắt đầu từ cổng vật lý và kết thúc bằng một ứng dụng bên trong máy ảo.

Tạo và nhận luồng bên trong máy chủ

Bước đầu tiên trong quá trình chuẩn bị TSDuck, chúng tôi sẽ tạo và nhận lưu lượng truy cập trong một máy chủ bằng cách sử dụng mạng.

Chuẩn bị môi trường:

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

Môi trường đã sẵn sàng. Chúng tôi khởi động trình phân tích lưu lượng truy cập:

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

trong đó "-p 1 -t 1" có nghĩa là bạn cần tính toán tốc độ bit mỗi giây và hiển thị thông tin về tốc độ bit mỗi giây
Chúng tôi khởi động trình tạo lưu lượng truy cập với tốc độ 10Mbps:

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

trong đó "-p 7 -e" có nghĩa là bạn cần gói 7 gói TS thành 1 gói IP và thực hiện chăm chỉ (-e), tức là. luôn đợi 7 gói TS từ bộ xử lý cuối cùng trước khi gửi gói IP.

Máy phân tích bắt đầu xuất ra các thông báo dự kiến:

* 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

Bây giờ thêm một số giọt:

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

và những thông báo như thế này xuất hiện:

* 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 

được mong đợi. Vô hiệu hóa tính năng mất gói (ip netns exec P iptables -F) và cố gắng tăng tốc độ bit của trình tạo lên 100Mbps. Máy phân tích báo cáo một loạt lỗi CC và khoảng 75 Mbps thay vì 100. Chúng tôi đang cố gắng tìm ra ai là người có lỗi - trình tạo không có thời gian hoặc vấn đề không nằm ở đó, vì điều này, chúng tôi bắt đầu tạo một số lượng cố định gói (700000 gói TS = 100000 gói 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

Như bạn có thể thấy, chính xác 100000 gói IP đã được tạo (151925460-151825460). Vì vậy, hãy tìm hiểu điều gì đang xảy ra với máy phân tích, đối với điều này, chúng tôi kiểm tra bộ đếm RX trên veth1, nó hoàn toàn bằng bộ đếm TX trên veth0, sau đó chúng tôi xem xét điều gì xảy ra ở cấp độ ổ cắm:

# 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 

Ở đây bạn có thể thấy số lượng giọt = 24355. Trong các gói TS, đây là 170485 hoặc 24.36% của 700000, vì vậy chúng tôi thấy rằng 25% tốc độ bit bị mất đó là những giọt trong ổ cắm udp. Sự sụt giảm trong ổ cắm UDP thường xảy ra do thiếu bộ đệm, hãy xem kích thước bộ đệm ổ cắm mặc định và kích thước bộ đệm ổ cắm tối đa:

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

Do đó, nếu ứng dụng không yêu cầu kích thước bộ đệm một cách rõ ràng, các ổ cắm sẽ được tạo với bộ đệm 208 KB, nhưng nếu chúng yêu cầu nhiều hơn, chúng vẫn sẽ không nhận được những gì được yêu cầu. Vì bạn có thể đặt kích thước bộ đệm bằng tsp cho đầu vào IP (-buffer-size), chúng tôi sẽ không chạm vào kích thước ổ cắm mặc định mà chỉ đặt kích thước bộ đệm ổ cắm tối đa và chỉ định rõ ràng kích thước bộ đệm thông qua các đối số 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

Với việc điều chỉnh bộ đệm ổ cắm này, hiện tại tốc độ bit được báo cáo là khoảng 100Mbps, không có lỗi CC.

Theo mức tiêu thụ CPU của chính ứng dụng tsp. So với CPU i5-4260U một lõi @ 1.40GHz, phân tích luồng 10Mbps sẽ yêu cầu 3-4% CPU, 100Mbps - 25%, 200Mbps - 46%. Khi cài đặt % Mất gói, tải trên CPU thực tế không tăng (nhưng có thể giảm).

Trên phần cứng hiệu quả hơn, có thể tạo và phân tích các luồng trên 1Gb / s mà không gặp vấn đề gì.

Kiểm tra trên card mạng thực

Sau khi thử nghiệm trên cặp veth, bạn cần lấy hai máy chủ hoặc hai cổng của một máy chủ, kết nối các cổng với nhau, khởi động trình tạo trên một máy chủ và máy phân tích trên máy chủ thứ hai. Không có gì bất ngờ ở đây cả, nhưng thực ra tất cả đều phụ thuộc vào sắt, ở đây càng yếu thì càng thú vị.

Sử dụng dữ liệu nhận được bởi hệ thống giám sát (Zabbix)

tsp không có bất kỳ API nào có thể đọc được bằng máy như SNMP hoặc tương tự. Các tin nhắn CC phải được tổng hợp trong ít nhất 1 giây (với tỷ lệ mất gói cao, có thể có hàng trăm/nghìn/chục nghìn mỗi giây, tùy thuộc vào tốc độ bit).

Vì vậy, để lưu cả thông tin và vẽ biểu đồ về lỗi CC và tốc độ bit và gây ra một số loại tai nạn, có thể có các tùy chọn sau:

  1. Phân tích và tổng hợp (theo CC) đầu ra của tsp, tức là chuyển đổi nó sang dạng mong muốn.
  2. Hoàn thiện chính tsp và/hoặc các plugin bộ xử lý bitrate_monitor và tính liên tục để kết quả được đưa ra ở dạng máy có thể đọc được phù hợp với hệ thống giám sát.
  3. Viết ứng dụng của bạn lên trên thư viện tsduck.

Rõ ràng, tùy chọn 1 là dễ dàng nhất về mặt nỗ lực, đặc biệt khi xem xét rằng bản thân tsduck được viết bằng ngôn ngữ cấp thấp (theo tiêu chuẩn hiện đại) (C ++)

Một nguyên mẫu trình phân tích cú pháp + trình tổng hợp bash đơn giản cho thấy rằng trên luồng 10Mbps và mất gói 50% (trường hợp xấu nhất), quy trình bash tiêu thụ CPU nhiều hơn 3-4 lần so với chính quy trình tsp. Kịch bản này là không thể chấp nhận được. Trên thực tế là một phần của nguyên mẫu này bên dưới

Mỳ ở trên

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

Ngoài việc chậm đến mức không thể chấp nhận được, không có luồng bình thường nào trong bash, các công việc bash là các quy trình riêng biệt và tôi phải ghi giá trị của gói thiếu mỗi giây một lần vào tác dụng phụ (khi nhận được thông báo tốc độ bit xuất hiện mỗi giây). Kết quả là, bash bị bỏ lại và người ta quyết định viết một trình bao bọc (trình phân tích cú pháp + trình tổng hợp) trong golang. Mức tiêu thụ CPU của mã golang tương tự ít hơn 4-5 lần so với chính quy trình tsp. Tốc độ tăng tốc của trình bao bọc do thay thế bash bằng golang hóa ra là khoảng 16 lần và nhìn chung kết quả là có thể chấp nhận được (chi phí CPU tăng 25% trong trường hợp xấu nhất). Tệp nguồn golang được đặt đây.

Chạy trình bao bọc

Để khởi động trình bao bọc, mẫu dịch vụ đơn giản nhất cho systemd đã được tạo (đây). Bản thân trình bao bọc được cho là sẽ được biên dịch thành tệp nhị phân (go build tsduck-stat.go) nằm trong /opt/tsduck-stat/. Giả định rằng bạn đang sử dụng golang có hỗ trợ đồng hồ đơn điệu (>=1.9).

Để tạo một phiên bản của dịch vụ, bạn cần chạy lệnh kích hoạt systemctl [email được bảo vệ]:1234 sau đó chạy với systemctl start [email được bảo vệ]: 1234.

Khám phá từ Zabbix

Để zabbix có thể khám phá các dịch vụ đang chạy thì thực hiện trình tạo danh sách nhóm (discovery.sh), ở định dạng cần thiết cho khám phá Zabbix, giả định rằng nó nằm ở cùng một vị trí - trong /opt/tsduck-stat. Để chạy khám phá qua zabbix-agent, bạn cần thêm tập tin .conf vào thư mục cấu hình zabbix-agent để thêm tham số người dùng.

Mẫu Zabbix

Mẫu đã tạo (tsduck_stat_template.xml) chứa quy tắc tự động phát hiện, nguyên mẫu mục, đồ thị và trình kích hoạt.

Danh sách kiểm tra ngắn gọn (tốt, nếu ai đó quyết định sử dụng nó)

  1. Đảm bảo rằng tsp không đánh rơi các gói trong điều kiện "lý tưởng" (máy phát và bộ phân tích được kết nối trực tiếp), nếu có hiện tượng rớt, hãy xem đoạn 2 hoặc nội dung của bài viết về vấn đề này.
  2. Hãy điều chỉnh bộ đệm ổ cắm tối đa (net.core.rmem_max=8388608).
  3. Biên dịch tsduck-stat.go (đi xây dựng tsduck-stat.go).
  4. Đặt mẫu dịch vụ vào /lib/systemd/system.
  5. Bắt đầu dịch vụ với systemctl, kiểm tra xem bộ đếm đã bắt đầu xuất hiện chưa (grep "" /dev/shm/tsduck-stat/*). Số lượng dịch vụ theo số lượng luồng multicast. Tại đây, bạn có thể cần tạo tuyến đường đến nhóm multicast, có thể tắt rp_filter hoặc tạo tuyến đường đến ip nguồn.
  6. Chạy Discovery.sh, đảm bảo nó tạo ra json.
  7. Thêm cấu hình tác nhân zabbix, khởi động lại tác nhân zabbix.
  8. Tải mẫu lên zabbix, áp dụng nó cho máy chủ đang được theo dõi và tác nhân zabbix đã được cài đặt, đợi khoảng 5 phút, xem có mục, biểu đồ và trình kích hoạt mới hay không.

Kết quả

Sử dụng TSDuck để giám sát luồng IP(TS)

Đối với nhiệm vụ phát hiện mất gói tin thì gần như là đủ, ít ra cũng còn hơn là không giám sát.

Thật vậy, “tổn thất” CC có thể xảy ra khi hợp nhất các đoạn video (theo như tôi biết, đây là cách thực hiện chèn tại các trung tâm truyền hình địa phương ở Liên bang Nga, tức là không tính toán lại bộ đếm CC), điều này phải được ghi nhớ. Các giải pháp độc quyền giải quyết một phần vấn đề này bằng cách phát hiện nhãn SCTE-35 (nếu được thêm bởi trình tạo luồng).

Về mặt giám sát chất lượng vận tải, thiếu giám sát jitter (IAT). Thiết bị TV (có thể là bộ điều biến hoặc thiết bị đầu cuối) có yêu cầu đối với thông số này và không phải lúc nào cũng có thể tăng jitbuffer lên vô cùng. Và jitter có thể nổi khi thiết bị có bộ đệm lớn được sử dụng trong quá trình truyền và QoS không được cấu hình hoặc cấu hình không đủ tốt để truyền lưu lượng thời gian thực như vậy.

Nguồn: www.habr.com

Thêm một lời nhận xét