Limitowanie sieci w systemie Linux na przykładzie cgroups i kolejkowania htb
W środowiskach serwerowych, gdzie wiele aplikacji i usług korzysta z zasobów współdzielonych, takich jak przepustowość sieci, precyzyjne zarządzanie ruchem sieciowym jest szalenie ważne dla zapewnienia stabilności i przewidywalnego działania systemu. W systemie CentOS Stream 9 na bazie, którego powstał niniejszy artykuł, wykorzystując mechanizmy cgroups v2 oraz zaawansowane narzędzia takie jak HTB (Hierarchical Token Bucket) w […]

W środowiskach serwerowych, gdzie wiele aplikacji i usług korzysta z zasobów współdzielonych, takich jak przepustowość sieci, precyzyjne zarządzanie ruchem sieciowym jest szalenie ważne dla zapewnienia stabilności i przewidywalnego działania systemu. W systemie CentOS Stream 9 na bazie, którego powstał niniejszy artykuł, wykorzystując mechanizmy cgroups v2 oraz zaawansowane narzędzia takie jak HTB (Hierarchical Token Bucket) w ramach `tc` (Traffic Control), administratorzy mogą skutecznie limitować przepustowość sieci dla poszczególnych procesów, usług lub użytkowników. Dzięki cgroups możliwe jest przypisanie klas sieciowych do konkretnych grup procesów, co w połączeniu z regułami HTB pozwala na stworzenie hierarchii priorytetów i precyzyjne ograniczanie przepustowości.
Takie świadome podejście do zarządzania siecią eliminuje ryzyko, że jedna aplikacja utylizuje na 100% zasoby sieciowe, co mogłoby negatywnie wpłynąć na inne usługi, takie jak serwery baz danych, systemy webowe czy aplikacje wymagające niskiego opóźnienia. Zarządzanie przepustowością na poziomie systemowym staje się zatem istotnym elementem nie tylko w kontekście stabilności i wydajności, ale także w kontroli kosztów i zgodności z wymaganiami SLA (Service Level Agreement). CentOS Stream 9 oferuje nowoczesne narzędzia i elastyczność w implementacji tych rozwiązań, czyniąc go odpowiednim wyborem dla środowisk wymagających szczegółowej kontroli zasobów sieciowych.
Wiemy już czym są grupy i jak wygląda limitowanie CPU czy Pamięci RAM. W tym artykule pokażę jak skutecznie limitować sieć. Wymaga to nieco więcej pracy i zrozumienia pewnych bardziej złożonych mechanizmów. Nie wystarczy jeden wpis do demona nginxa, należy zrozumieć nieco inne mechanizmy. Ograniczenie przepustowości sieci wymaga kilku kroków. Na przykładzie usługi nginx pokażę, jak skonfigurować ograniczenie przepustowości do 1 MB/s. Będzie to najłatwiejsze do pokazania niż w przypadku innych aplikacji, ale mechanizm można zastosować do dowolnej innej usługi w systemie Linux.
Konfiguracja limitowania
Limitowanie odbywa się za pomocą narzędzie traffic control ‘tc’, które jest dostępne w systemach Linux i umożliwia szczegółowe zarządzanie ruchem sieciowym na poziomie interfejsów sieciowych. Jest częścią pakietu narzędzi iproute2 i pozwala na tworzenie zaawansowanych reguł kontroli przepustowości, priorytetyzacji, filtrowania oraz kształtowania ruchu (traffic shaping). Dzięki `tc` administratorzy mogą precyzyjnie zarządzać dostępną przepustowością, na przykład ograniczając prędkość wysyłania lub odbierania danych dla konkretnych portów, adresów IP czy aplikacji.
Mechanizmem wykorzystywanym przez ‘tc’ jest hierarchiczny podział kolejek (HTB, ang. Hierarchical Token Bucket), który pozwala na przydzielanie określonych zasobów sieciowych grupom użytkowników lub procesom, jednocześnie umożliwiając zachowanie hierarchii priorytetów w przypadku większego obciążenia sieci. Narzędzie to jest szczególnie przydatne w środowiskach serwerowych i wielodostępnych, gdzie konieczne jest zapewnienie stabilności usług poprzez ograniczanie i zarządzanie ruchem generowanym przez poszczególne aplikacje lub użytkowników, zapobiegając zabieraniu zasobów sieciowych przez jeden proces kosztem innych.
Ustawienie limitu:
mkdir -p /sys/fs/cgroup/system.slice/nginx.slice
Tworzymy główną kolejkę HTB na interfejsie eth0, która będzie zarządzać całym ruchem sieciowym dla tego interfejsu. Kolejne klasy i filtry będą działały w ramach tej kolejki.
tc qdisc add dev eth0 root handle 1: htb
Legenda:
tc: Wywołanie narzędzia Traffic Control.
qdisc add: Dodanie „kolejki dyscyplin” (ang. queuing discipline) dla interfejsu sieciowego. Kolejki definiują sposób zarządzania ruchem sieciowym na poziomie interfejsu.
dev eth0: Wskazuje, że operacja dotyczy interfejsu sieciowego eth0.
root: Określa, że jest to główna kolejka (ang. root qdisc) dla tego interfejsu.
handle 1:: Ustawia identyfikator kolejki na 1:, który będzie używany w dalszych liniach do odwoływania się do tej kolejki.
htb: Wskazuje, że używana jest kolejka typu HTB (Hierarchical Token Bucket). HTB umożliwia precyzyjne zarządzanie przepustowością, dzieląc dostępne zasoby na klasy z określonymi limitami.
Tworzymy klasę w ramach głównej kolejki HTB, która ogranicza przepustowość do 1 Mb/s. Klasa ta będzie używana do kontrolowania ruchu przypisanego przez filtry w kolejnych krokach.
tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit
Legenda:
tc class add: Dodanie nowej klasy w ramach wcześniej utworzonej kolejki.
dev eth0: Wskazuje, że klasa dotyczy interfejsu eth0.
parent 1:: Określa, że klasa jest przypisana do kolejki nadrzędnej o identyfikatorze 1: (utworzonej w poprzedniej linii).
classid 1:1: Ustawia identyfikator klasy na 1:1. Każda klasa musi mieć unikalny identyfikator w ramach swojej kolejki nadrzędnej.
htb: Określa, że ta klasa korzysta z HTB.
rate 1mbit: Ustawia maksymalną przepustowość dla tej klasy na 1 megabit na sekundę.
Tworzymy filtr, który identyfikuje ruch HTTP (pakiety o porcie źródłowym 80) i przypisuje go do klasy 1:1. Dzięki temu ruch HTTP na porcie 80 będzie podlegał ograniczeniom przepustowości ustawionym w tej klasie (1 Mb/s).
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 80 0xffff flowid 1:1
Legenda:
tc filter add: Dodanie filtra, który przypisuje określony ruch do wcześniej utworzonej klasy.
dev eth0: Wskazuje, że filtr dotyczy interfejsu eth0.
protocol ip: Filtruje pakiety zgodnie z protokołem IP.
parent 1:: Określa, że filtr działa w ramach kolejki nadrzędnej 1:.
prio 1: Ustawia priorytet filtra. Priorytet definiuje, które filtry są oceniane jako pierwsze, jeśli istnieje więcej niż jeden filtr.
u32: Używa klasyfikatora u32, który pozwala na dopasowanie pakietów na podstawie dowolnych pól w nagłówkach.
match ip sport 80 0xffff: Dopasowuje pakiety, których port źródłowy wynosi 80 (standardowy port HTTP). Wartość 0xffff oznacza maskę bitową, która sprawia, że filtr bierze pod uwagę całe 16-bitowe pole portu.
flowid 1:1: Przypisuje ruch pasujący do filtra do klasy o identyfikatorze 1:1
W tym przykładzie limitujemy ruch na porcie 80, ale nic nie stoi na przeszkodzie, żeby zrobić to samo dla portu 443 i innych, np. jeśli chcielibyśmy limitować jedynie usługę poczty elektronicznej na porcie 25.
tc qdisc add dev eth0 root handle 1: htb
tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 80 0xffff flowid 1:1
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 443 0xffff flowid 1:1
tc filter add dev eth0 protocol ip parent 1: prio 1 u32 match ip sport 25 0xffff flowid 1:1
Możliwości jest wiele i tylko od kreatywności administratora i potrzeb danego środowiska zależy jak bardzo zostanie to rozbudowane.
Testy
Pobieranie pliku
Modyfikacja i podniesienie limitu
Może zdarzyć się tak, że będziemy chcieli podnieść limit z 1 Mb/s do 5 Mb/s. Wystarczy zmodyfikować istniejącą kolejkę HTB i zwiększyć limit.
tc class change dev eth0 parent 1: classid 1:1 htb rate 5mbit
Plik nie musi być przerwany do ponownego pobrania. Zaaplikowanie zmian odbywa się natychmiast, od razu po wprowadzeniu modyfikacji zarówno w górę jak i w dół.
Warto wspomnieć, że limitowanie to nie jest permanentne i po restarcie systemu wartości nie załadują się automatycznie. Aby ustawić permanentne limitowanie należałoby w tym miejscu utworzyć skrypt bash, który będzie ładowany przy starcie systemu i ładujący limity automatycznie lub stworzenie serwisu dla systemd, który będzie ładowany wraz ze startem systemu.