Pokazuję, jak Kształtowanie przepustowości na serwerach i kontroli ruchu w systemie Linux, aby kontrolować przepływy pakietów w taki sposób, że opóźnienia, jitter i przestoje są zauważalnie zmniejszone. Używam priorytetowych kolejek, limitów i reguł QoS do ochrony krytycznych przepływów biznesowych, takich jak VoIP, API lub żądania sklepowe przed obciążeniami w tle i kopiami zapasowymi.
Punkty centralne
Poniższe kluczowe stwierdzenia pomagają mi kontrolować przepustowość i ruch na serwerach Linux w sposób ukierunkowany i umożliwiający ich stałe planowanie.
- Ustalanie priorytetów Przepływy krytyczne czasowo zmniejszają opóźnienia i zakłócenia.
- Limity stawek i ograniczanie przepustowości pozwalają uniknąć przerw i zacięć bufora.
- HTB/SFQ sprawiedliwie rozdzielać przepustowość i utrzymywać klasy na stałym poziomie.
- Filtr QoS kontrola przez IP, port, protokół lub tagi.
- Monitoring poprzez P95 i alerty wykrywa wąskie gardła na wczesnym etapie.
Buduję te punkty krok po kroku, stale mierzę efekty i dostosowuję klasy i stawki do rzeczywistego wykorzystania.
Co właściwie oznacza kształtowanie przepustowości
Podczas kształtowania reguluję Przepływ paczek aktywnie zamiast tylko reaktywnego ograniczania przepustowości. Utrzymuję stałe stawki, nadaję priorytet ruchowi w czasie rzeczywistym i interaktywnemu oraz wygładzam nieregularne impulsy danych. Aby to zrobić, używam ograniczania szybkości dla ruchu wychodzącego i dławienia dla przychodzących strumieni danych. Taka separacja tworzy wyraźne obowiązki w każdym kierunku i zapobiega zapełnianiu buforów. W przypadku środowisk hostingowych ustawiam zdefiniowane górne limity dla każdego klienta lub aplikacji, aby szczyt obciążenia nie spowalniał całego systemu.
Kontrola ruchu w systemie Linux: narzędzia i koncepcje
Pod Linuksem kontroluję ruch za pomocą narzędzia tc i dyscypliny kolejkowania jądra (qdisc). Typowe bloki konstrukcyjne to root qdisc, klasy i filtry, które definiują przypisanie pakietów do priorytetów i limitów. Często zaczynam od HTB jako hierarchicznego kontrolera dla gwarantowanych i maksymalnych szybkości. Używam również SFQ do sprawiedliwej dystrybucji w obrębie klasy. Ograniczam przepustowość do 90-95 procent fizycznie możliwej szybkości, aby zachować zapas burst i uniknąć szczytów opóźnień.
Kształtowanie wejścia (Ingress): IFB zamiast Policer
Dla ruchu przychodzącego, nie formuję bezpośrednio na interfejsie fizycznym, ale używam IFB-device (Intermediate Functional Block). Kopiuję pakiety przychodzące do IFB i traktuję je tam jak ruch wychodzący - w tym hierarchię HTB, sprawiedliwość i limity. To jest drobniejszy niż czysty policer, który odrzuca tylko trudne i często zwiększa jitter.
modprobe ifb numifbs=1
ip link add ifb0 type ifb
ip link set dev ifb0 up
# Aktywuj ingress na PHY i przekieruj do IFB
tc qdisc add dev eth0 handle ffff: ingress
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 \
action mirred egress redirect dev ifb0
# Shaping na IFB jak w przypadku egress
tc qdisc add dev ifb0 root handle 2: htb default 20
tc class add dev ifb0 parent 2: classid 2:10 htb rate 40mbit ceil 60mbit
tc class add dev ifb0 parent 2: classid 2:20 htb rate 20mbit ceil 40mbit
tc qdisc add dev ifb0 parent 2:10 handle 210: fq_codel
tc qdisc add dev ifb0 parent 2:20 handle 220: sfq
Dzięki IFB zyskuję kontrolę nad szczytami pobierania, na przykład gdy przychodzące zadania tworzenia kopii zapasowych lub kopii lustrzanych wiążą przepustowość. W praktyce używam IFB na interfejsach o wysoce asymetrycznych szybkościach (np. 1G/200M) lub tam, gdzie przychodzące impulsy zagrażają interaktywności.
Porównanie HTB, TBF i SFQ
Dla właściwego wyboru qdisc Patrzę na cele aplikacji: Gwarancje, zachowanie burst i sprawiedliwość. HTB oferuje hierarchiczne klasy ze stałymi i maksymalnymi stawkami, TBF ściśle ogranicza token bucket, SFQ dystrybuuje możliwości poprzez przepływy. W połączeniu tworzą one odporną strukturę w praktyce: HTB ogranicza i gwarantuje, SFQ zapobiega dominacji poszczególnych połączeń, TBF oswaja uporczywe wybuchy. Poniższa tabela podsumowuje podstawowe funkcje dla typowych scenariuszy serwerowych. Pozwala to szybciej zdecydować, która dyscyplina ma sens w danym momencie.
| qdisc/Feature | Cel | Mocne strony | Typowe zastosowanie |
|---|---|---|---|
| HTB | Hierarchia i kontrola szybkości | Stawka gwarantowana, górny limit, dziedziczenie | Klienci, klasy usług, profile QoS |
| TBF | Ścisły Pokrywy | Prosty, bardzo deterministyczny | Limit połączeń w górę, twarde limity aplikacji |
| SFQ | Sprawiedliwość na przepływ | Niskie koszty ogólne, dobra dystrybucja | Pobieranie, P2P, wiele sesji |
| FQ_CoDel | AQM przeciwko bufferbloat | Niskie opóźnienia, niezakodowana kolejka | Routery brzegowe, łącza o krytycznym opóźnieniu |
W przypadku dostępów o znacznie zmiennych RTT używam FQ_CoDel lub - w zależności od jądra - CAKE jako uniwersalnego rozwiązania. W praktyce serwerowej trzymam się jednak HTB+SFQ/FQ_CoDel, ponieważ mogę połączyć gwarancje, pożyczanie i sprawiedliwą dystrybucję w hierarchii.
Praktyka: zasady tc dla typowych serwerów
Zaczynam od prostego HTB-struktura, a następnie przydzielić za pomocą filtra. Główny dysk qdisc z domyślną klasą wyłapuje niesklasyfikowane pakiety, klasy priorytetowe otrzymują gwarantowane stawki. Następnie doprecyzowuję filtry: HTTP/S do klasy A, replikacja bazy danych do klasy B, kopie zapasowe do klasy C. Dzięki temu żądania sklepowe są szybkie, podczas gdy kopie zapasowe wykorzystują resztki. Aby zapoznać się z podstawami i słownictwem, odsyłam do tego wprowadzenia do Zarządzanie przepustowością, co czyni procedurę namacalną.
tc qdisc add dev eth0 root handle 1: htb default 20
tc class add dev eth0 parent 1: classid 1:10 htb rate 50mbit ceil 70mbit
tc class add dev eth0 parent 1: classid 1:20 htb rate 20mbit ceil 50mbit
tc class add dev eth0 parent 1: classid 1:30 htb rate 10mbit ceil 30mbit
tc qdisc add dev eth0 parent 1:10 handle 110: sfq
tc qdisc add dev eth0 parent 1:20 handle 120: sfq
tc qdisc add dev eth0 parent 1:30 handle 130: sfq
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 443 0xffff flowid 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip dport 3306 0xffff flowid 1:20
tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip sport 22 0xffff flowid 1:30
Klasyfikacja za pomocą DSCP i znaczników (z obsługą IPv4/IPv6)
Aby upewnić się, że filtry działają niezależnie od wersji IP i NAT, oznaczam pakiety wcześniej, a następnie mapuję je przez fwmark w klasach. Oszczędza mi to skomplikowanych dopasowań u32 i utrzymuje reguły na niskim poziomie. Używam również DSCP do semantyki end-to-end, np. dla VoIP lub interaktywności.
Przykład # z nftables: Priorytet TLS, dławienie kopii zapasowych
nft add table inet mangle
nft add chain inet mangle prerouting { type filter hook prerouting priority -150; }
nft add rule inet mangle prerouting tcp dport 443 meta mark set 10
nft add rule inet mangle prerouting tcp dport 22 meta mark set 30
nft add rule inet mangle prerouting tcp dport 873 meta mark set 40 # rsync/Backups
Mapowanie # w klasach HTB (działa jednakowo dla IPv4/IPv6)
tc filter add dev eth0 parent 1:0 prio 1 handle 10 fw flowid 1:10
tc filter add dev eth0 parent 1:0 prio 2 handle 30 fw flowid 1:30
tc filter add dev eth0 parent 1:0 prio 3 handle 40 fw flowid 1:20
Ważne: ustawiam DSCP/znaczniki tak daleko, jak to możliwe. na krawędzi (wejście maszyny lub przed nią), dzięki czemu późniejsze decyzje mogą być podejmowane szybko, a tc ma mniej pracy do wykonania pod obciążeniem.
Strategie QoS dla hostingu: sprawiedliwość i ograniczenia
W konfiguracjach z wieloma dzierżawcami zabezpieczam Sprawiedliwość poprzez stałe gwarancje na klienta i limity na aplikację. Oznaczam pakiety za pomocą DSCP lub według portów i przypisuję je do odpowiednich klas. Pobieranie i kopie zapasowe są dozwolone do wypełnienia pojemności, podczas gdy sesje interaktywne są traktowane priorytetowo. W ten sposób usługi istotne z punktu widzenia SLA pozostają priorytetowe bez wykluczania innych dzierżawców. W tym przeglądzie podsumowałem praktyczne scenariusze i logikę ustalania priorytetów Priorytetyzacja ruchu co dobrze pasuje do zasad tc.
Trwałość i automatyzacja
Moje zasady QoS przetrwają restarty i ponowne uruchomienie interfejsu. Przechowuję polecenia tc jako skrypt idempotentny i integruję go z systemd lub netplan/networkd. Dla urządzeń z dynamicznymi nazwami (np. veth/tap) używam reguł udev lub szablonów systemd.
# /usr/local/sbin/tc-setup.sh (kompilacja idempotentna)
#!/bin/sh
tc qdisc replace dev eth0 root handle 1: htb default 20
# ... więcej klas/filtrów tutaj
# systemd unit: /etc/systemd/system/tc-setup.service
[Jednostka]
Description=Konfiguracja kontroli ruchu
After=network-online.target
Chce=network-online.target
[Usługa]
Type=oneshot
ExecStart=/usr/local/sbin/tc-setup.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Wdrażam zmiany w kontrolowany sposób: najpierw na staging, a następnie przez ograniczony czas w systemie produkcyjnym (wymiana tc zamiast dodać), wraz z metrykami i przyciskiem wycofania.
Monitorowanie, P95 i rozwiązywanie problemów bez frustracji
Mierzę efekty w sposób ciągły, zamiast skupiać się na Przeczucie do opuszczenia. Opóźnienia P95, długości kolejek i straty pakietów pokazują, czy reguły są skuteczne, czy zbyt rygorystyczne. Narzędzia takie jak iftop, vnStat i Netdata uwidaczniają szczyty obciążenia, logi z tc i iptables pokazują alokację. Jeśli wystąpi jitter, nieznacznie zmniejszam wartości ceil i sprawdzam CoDel/FQ_CoDel jako miarę AQM. W przypadku wąskich gardeł dostosowuję wagi klas krok po kroku i utrzymuję okna pomiarowe po każdej zmianie.
Metodologia testów: symulacja i weryfikacja obciążenia
Symuluję realistyczne scenariusze: ciągły przepływ (iperf3), krótkie interakcje (małe żądania HTTP) i okresowe wybuchy (backup/rsync) równolegle. Następnie sprawdzam, czy interaktywne przepływy utrzymują konsekwentnie niskie opóźnienia i czy wybuchy są wygładzane w czysty sposób.
# Test w przeciwnym kierunku (download/ingress)
iperf3 -c -R -t 60
# Odczyt statystyk kształtowania
tc -s qdisc show dev eth0
tc -s class show dev eth0
# Sprawdzenie rozkładu jittera/RTT
ping -i 0.2 -c 100 | awk '/time=/{print $7}' Jeśli klasy potrzebują stałych pożyczek, nieznacznie zwiększam gwarantowane stawki. Jeśli spadki gromadzą się w kolejkach AQM, sprawdzam rozmiary buforów i czy limity nie są ustawione zbyt agresywnie.
Strojenie wydajności: pokrycie 90-95 %, wygładzanie serii, MTU
Ograniczam szybkość wyjściową do 90-95% prędkości łącza, aby uniknąć przepełnienia bufora i umożliwić działanie AQM. Wygładzam impulsy za pomocą parametrów token bucket (rate, burst/latency), aby krótkoterminowe szczyty nie wypełniały całych kolejek. Sprawdzam MTU, aby zmniejszyć fragmentację i uniknąć problemów z MTU ścieżki. W przypadku bardzo zmiennych obciążeń ustawiam wysokie wartości ceil, ale konserwatywne gwarantowane szybkości. Taka konfiguracja utrzymuje szybki ruch priorytetowy, podczas gdy procesy w tle nadal działają neutralnie.
Odciążenia sprzętowe, dostrajanie wielu kolejek i IRQ
Jeśli chodzi o precyzyjne kształtowanie na szybkich łączach, znam interakcję z offloadami NIC. TSO/GSO/GRO przyspieszają, ale przy bardzo niskich prędkościach docelowych mogą pogorszyć drobnoziarnistość. W przypadku wrażliwych łączy wyłączam TSO/GSO w ramach testu i mierzę opóźnienie/wzrost wydajności procesora. Na kartach sieciowych z wieloma kolejkami używam metody mq-Rozkładam obciążenie CPU za pomocą RPS/XPS i IRQ pinning, tak aby praca QoS nie była zagłodzona na CPU.
# Selektywne testowanie odciążeń (ostrożne w produkcji)
ethtool -K eth0 tso off gso off gro off
# Układ wielu kolejek
tc qdisc add dev eth0 root handle 1: mq
tc qdisc add dev eth0 parent 1:1 handle 10: htb default 20
tc qdisc add dev eth0 parent 1:2 handle 20: htb default 20
# ... kontynuuj dla każdej kolejki i ustaw klasy/filtry jak zwykle
Z txqueuelen, Rozmiary buforów pierścieniowych i powinowactwo IRQ, kontynuuję przycinanie opóźnień. Celem jest osiągnięcie stabilnej, krótkiej ścieżki kolejki, która nie przewraca się pod obciążeniem.
Bezpieczeństwo i segmentacja: kształtowanie za pomocą zapory sieciowej i sieci VLAN
Łączę QoS z Segmentacja, dzięki czemu krytyczne sieci zachowują swoją własną przepustowość. Ustawiam własne kolejki dla każdej sieci VLAN lub interfejsu, firewalle oznaczają pakiety, gdy tylko wejdą na serwer. Oznacza to, że tc musi podejmować mniej decyzji pod obciążeniem, ponieważ pakiety są klasyfikowane na wczesnym etapie. Kopie zapasowe z sieci VLAN pamięci masowej pozostają na swojej ścieżce, podczas gdy frontend HTTP nie głoduje. Separacja skraca również analizy błędów, ponieważ przepływy mogą być przypisywane w bardziej przejrzysty sposób.
Wirtualizacja i kontenery: Gdzie jestem
W konfiguracjach KVM/virtio wolę tworzyć Krawędźna interfejsie bridge (br0), na fizycznym łączu uplink (eth0) lub konkretnie dla każdego gościa na jego interfejsie vnet. Lubię wdrażać gwarancje per-tenant na vnetX, globalne limity na uplinku. W Kubernetes, tc jest wykonalne na peerach veth lub uplinkach węzłów; przypisuję markery na wczesnym etapie poprzez CNI/iptables/nftables, aby alokacja pozostała deterministyczna. W przypadku SR-IOV lub DPDK upewniam się, że ścieżki danych w ogóle przechodzą przez tc - w przeciwnym razie tworzę wcześniej lub używam własnych ograniczników szybkości NIC.
Koszty i korzyści: Wydajność zamiast modernizacji sprzętu
Z czystym Kształtowanie Lepiej wykorzystuję istniejące łącza i często oszczędzam na kosztownych modernizacjach. Mniejsza utrata pakietów i niższe opóźnienia bezpośrednio poprawiają wrażenia użytkowników. W środowiskach hostingowych opłaca się to podwójnie, ponieważ uczciwe limity zapobiegają eskalacji między klientami. W praktyce widzę, że stabilne stawki zwiększają przepustowość, ponieważ retransmisje są ograniczone. Efekty te są ostatecznie odzwierciedlone w bardziej przejrzystych umowach SLA i mniejszej liczbie przypadków pomocy technicznej.
Częste pułapki i szybkie kontrole
- Niewłaściwe jednostki: Sprawdzam, czy
mbitorazkbitsą zapisywane poprawnie, a burst/latency są zgodne z MTU. - Odwrócenie priorytetów: Zbyt wiele klas o wysokim priorytecie bez rzeczywistego limitu prowadzi do głodu domyślnych. Ściśle przestrzegam górnych limitów.
- Pominięto NAT/IPv6: Filtry portów nie działają zgodnie z przeznaczeniem po NAT/IPv6. Zaznaczam wcześnie (fwmark), a następnie mapuję w klasach.
- Ceil less than rate: Powszechna literówka, która blokuje pożyczanie. Sprawdzam poprawność każdej klasy za pomocą
tc -s class. - Ingress tylko spolaryzowany: Twardy dropping tworzy jitter. Z IFB kształtuję dokładniej i sprawiedliwiej.
- Przeciążenia zniekształcają pomiary: Dokumentuję stan odciążenia dla każdego testu i porównuję jabłka z jabłkami.
Perspektywy na przyszłość: Rezerwacje wspierane przez sztuczną inteligencję i polityki adaptacyjne
Używam trendów takich jak Przewidywania na podstawie historycznego obciążenia, aby dynamicznie dostosowywać klasy na krótko przed godzinami szczytu. Modele uczące się rezerwują przepustowość dla VoIP lub faz kasowych przed wzrostem kolejek. W sieciach hybrydowych między chmurą a siecią lokalną używam tymczasowych limitów i budżetów typu burst, które zmieniają zasady zgodnie z harmonogramem. Zmniejsza to liczbę interwencji operacyjnych i utrzymuje przewidywalność usług nawet podczas specjalnych wydarzeń. Więcej informacji na temat skalowania i limitów można znaleźć tutaj: Zarządzanie ruchem i limity hostingu.
Podsumowanie i lista kontrolna
Najpierw ustawiłem wyraźny Hierarchia z HTB, wystawiam gwarancje i utrzymuję Ceil nieco poniżej prędkości łącza. Następnie klasyfikuję według usług, protokołów lub DSCP i sprawdzam opóźnienia, jitter i wartości P95. Używam SFQ lub FQ_CoDel, aby zapewnić sprawiedliwą dystrybucję i krótkie kolejki. Monitorowanie towarzyszy każdej zmianie, dzięki czemu mogę decydować o efektach zamiast zgadywać. Oznacza to, że kształtowanie przepustowości nie jest jednorazowym działaniem, ale szczupłą pętlą kontrolną, która utrzymuje bezpieczny i przewidywalny ruch serwerów.


