limity zasobów cgroups v2 z systemd
11 min czytania - 3 czerwca 2026

Ustawianie limitów CPU, pamięci i I/O za pomocą cgroups v2 i systemd. Praktyczna konfiguracja dla hostów Linux z wieloma dzierżawcami, z monitorowaniem PSI i izolacją wycinków.
Limity zasobów cgroups v2 w systemd
cgroups v2 to ujednolicona struktura kontroli zasobów jądra systemu Linux. Zastępuje ono fragmentaryczną hierarchię v1 pojedynczym drzewem, które spójnie obsługuje procesor, pamięć i operacje wejścia/wyjścia oraz stanowi podstawę izolacji kontenerów w Dockerze, Kubernetesie i systemd. Ten post opisuje, jak włączyć cgroups v2, ustawić limity za pomocą systemd i zastosować to w rzeczywistych scenariuszach hostingu wielodostępnego.
Włączanie cgroups v2
Nowoczesne dystrybucje mają domyślnie włączone cgroups v2: Ubuntu 21.10+, Debian 11+, Fedora 31+ oraz RHEL/Rocky 9+. Starsze systemy mogą działać w hierarchii hybrydowej lub nadal domyślnie korzystać z wersji v1. Sprawdź za pomocą:
stat -fc %T /sys/fs/cgroup/
Wynik polecenia cgroup2fs potwierdza, że wersja v2 jest aktywna. tmpfs zazwyczaj oznacza wersję v1.
Aby przełączyć system hybrydowy na czystą wersję v2, edytuj /etc/default/grub i dodaj następujący wpis do GRUB_CMDLINE_LINUX_DEFAULT:
systemd.unified_cgroup_hierarchy=1 cgroup_no_v1=all
Następnie wygeneruj ponownie GRUB i uruchom ponownie system:
sudo update-grub
sudo reboot
W środowisku produkcyjnym uruchom jądro 5.2 lub nowsze, aby uzyskać zamrażarkę cgroup dla v2 oraz systemd 244+ dla pełnej cpuset delegacji. W systemach Rocky Linux 8 i RHEL 8 może być również konieczne wyraźne włączenie rozliczania poprzez dodanie tych wierszy do /etc/systemd/system.conf:
DefaultCPUAccounting=yes
DefaultMemoryAccounting=yes
DefaultIOAccounting=yes
Przeładuj za pomocą sudo systemctl daemon-reexec. Po ponownym uruchomieniu sprawdź, które kontrolery są dostępne:
cat /sys/fs/cgroup/cgroup.controllers
Powinieneś zobaczyć cpu, memory, ioi pids wykaz. Kontrolery te nie są domyślnie włączone dla podrzędnych grup cgroup. Aby je aktywować, zapisz w pliku kontrolnym poddrzewa root:
echo "+cpu +memory +io" | sudo tee /sys/fs/cgroup/cgroup.subtree_control
Aby uzyskać szczegółowy przegląd tego, czym wersja v2 różni się wewnętrznie od wersji v1, najlepszym źródłem informacji jest wykład Michaela Kerriska wygłoszony podczas NDC TechTown:
Jak systemd organizuje cgroups
systemd tworzy cgroup dla każdej uruchamianej usługi, nazywając ją zgodnie z nazwą jednostki. nginx.service pobiera /sys/fs/cgroup/system.slice/nginx.service/, a każdy uruchamiany przez nią proces działa w ramach tej grupy cgroup. Trzy typy jednostek odpowiadają bezpośrednio hierarchii:
| Typ jednostki | Rola | Opis |
|---|---|---|
.slice | Węzeł wewnętrzny | Grupuje powiązane usługi i definiuje wspólne limity |
.service | Węzeł końcowy | Zarządza procesami uruchomionymi przez systemd |
.scope | Węzeł liścia | Śledzi procesy uruchomione zewnętrznie (ładunki kontenerów, sesje logowania) |
Cztery domyślne segmenty są dostarczane w standardzie: -.slice (root), system.slice, user.slicei machine.slice. Każde ograniczenie zastosowane do segmentu automatycznie dotyczy każdej usługi w nim zawartej.
Jedna zasada w wersji 2, o której warto pamiętać: procesy mogą istnieć tylko w węzłach liściowych. Grupa cgroup z podgrupami cgroup nie może bezpośrednio hostować procesów, dlatego systemd nigdy nie umieszcza usług w pniu segmentu.
Zawsze należy ustawiać ograniczenia za pośrednictwem systemd, a nie zapisując je /sys/fs/cgroup/ . Ręczne zapisy nie są zachowywane po ponownym uruchomieniu i kolidują z wyłączną własnością hierarchii przez systemd. Użyj systemctl set-property do jednorazowych zmian i wtyczek jednostek (systemctl edit nginx.service) do zmian stałych.
Ograniczenia procesora
cgroups v2 oferuje dwie opcje kontroli procesora: twardy limit (cpu.max, udostępniony jako CPUQuota w systemd) oraz proporcjonalną wagę (cpu.weight / CPUWeight).
CPUQuota jest to absolutny pułap. CPUQuota=50% pozwala na wykorzystanie połowy rdzenia; CPUQuota=200% pozwala na wykorzystanie czasu odpowiadającego dwóm pełnym rdzeniom. Usługa jest ograniczana, jeśli próbuje przekroczyć ten limit, niezależnie od tego, jak bardzo reszta procesora jest niewykorzystana.
CPUWeight ma znaczenie tylko w przypadku rywalizacji o zasoby. Zakres wynosi od 1 do 10 000, domyślnie 100. Trzy usługi o wagach 150, 100 i 50 otrzymują w przybliżeniu 50%, 33% i 17% czasu procesora, gdy wszystkie chcą go w tym samym czasie. Gdy procesor jest w innym przypadku bezczynny, wagi niczego nie ograniczają.
W przypadku obciążeń wrażliwych na opóźnienia, przypisuj procesy do konkretnych rdzeni za pomocą AllowedCPUs=. Zmniejsza to liczbę przełączania kontekstu i utrzymuje pamięć podręczną każdego rdzenia w stanie aktywnym:
[Service]
CPUQuota=200%
CPUWeight=150
AllowedCPUs=0-3
Użyj twardego limitu, gdy potrzebujesz przewidywalnych kosztów (rozliczenia wielodostępne, izolacja od hałaśliwych sąsiadów). Użyj wag, gdy chcesz maksymalnie wykorzystać sprzęt i potrzebujesz ustalenia kolejności priorytetów tylko podczas szczytów obciążenia.
Ograniczenia pamięci w cgroups v2
Pamięć ma dwa poziomy: memory.high (miękki, ograniczający przepustowość) oraz memory.max (twardy, OOM). Aby uzyskać informacje na temat pamięci wymiany, odzyskiwania stron i mechanizmu OOM killer jądra, zapoznaj się z naszym dodatkowym wpisem na temat zarządzania pamięcią w systemie Linux.
Ustaw memory.high około 10 do 20% poniżej memory.max. Jądro zaczyna odzyskiwać strony i dławić alokacje po memory.high , co zazwyczaj pozwala na przywrócenie wydajności obciążenia, zanim uruchomi się mechanizm OOM. Jeśli zużycie osiągnie memory.max, jądro zabija procesy w cgroup.
Typowa konfiguracja:
[Service]
MemoryHigh=400M
MemoryMax=512M
MemorySwapMax=0
MemorySwapMax=0 wyłącza swap dla tej cgroup. Warto to zrobić w przypadku obciążeń wrażliwych na opóźnienia (bazy danych, strumieniowanie w czasie rzeczywistym), gdzie operacje wejścia/wyjścia na swapie mogłyby znacznie zwiększyć opóźnienie ogona.
W przypadku pul pracowników, gdzie pozostawienie osieroconych procesów siostrzanych mogłoby uszkodzić stan współdzielony, należy wpisać 1 do pliku memory.oom.group . Gdy jeden proces zostanie zabity z powodu braku pamięci (OOM), jądro zabija jednocześnie wszystkie procesy w cgroup.
Sprawdź memory.events , aby sprawdzić, jak często usługa była ograniczana lub zabijana przez OOM:
cat /sys/fs/cgroup/system.slice/nginx.service/memory.events
Pole high i oom_kill wskazują, czy limity są ustawione prawidłowo. Trwałe wartości niezerowe oznaczają, że obciążenie wymaga większego zapasu mocy obliczeniowej.
Ograniczenia we/wy
Kontroler I/O ma tę samą konstrukcję dwumodową: bezwzględne ograniczenia poprzez io.max oraz proporcjonalne współdzielenie poprzez io.weight.
Limity dotyczą poszczególnych urządzeń blokowych, identyfikowanych przez numery major:minor. Znajdź je za pomocą lsblk -o NAME,MAJ:MIN. Typowa konfiguracja systemd:
[Service]
IOReadBandwidthMax=/dev/sda 50M
IOWriteBandwidthMax=/dev/sda 30M
IOReadIOPSMax=/dev/sda 1000
IOWriteIOPSMax=/dev/sda 500
io.weight działa tak jak cpu.weight: zakres od 1 do 10 000, domyślnie 100. Przypisanie wartości 500 do usługi dla klientów i 50 do nocnej kopii zapasowej zapobiega przeciążeniu dysku przez kopię zapasową w godzinach szczytu, ale pozwala jej wykorzystać pełną przepustowość, gdy niczego innego nie potrzeba.
Limity I/O mają zastosowanie tylko wtedy, gdy są skierowane do właściwego urządzenia. Jądro śledzi operacje I/O według urządzeń blokowych, więc limit na /dev/sda nie ma wpływu na operacje wejścia/wyjścia kierowane do /dev/nvme0n1. Na hostach z wieloma dyskami należy ustawić limity dla poszczególnych urządzeń.
Izolacja wielodostępna z wykorzystaniem segmentów
W przypadku środowisk współdzielonych należy zdefiniować segment dla każdego dzierżawcy. Utworzenie /etc/systemd/system/tenant-a.slice:
[Slice]
CPUQuota=200%
CPUWeight=150
MemoryHigh=3584M
MemoryMax=4096M
MemorySwapMax=0
IOReadBandwidthMax=/dev/sda 200M
TasksMax=512
TasksMax=512 ogranicza całkowitą liczbę procesów i wątków, co zapobiega sytuacji, w której fork bomb u jednego dzierżawcy powoduje awarię hosta. Umieść usługi dzierżawcy w tym segmencie (poprzez Slice=tenant-a.slice w ich plikach jednostkowych), a automatycznie odziedziczą one wszystkie ustawienia.
Ten wzorzec sprawdza się również przy oddzielaniu hałaśliwych zadań w tle od usług widocznych dla użytkownika. Umieść kopie zapasowe, rotację logów i zadania wsadowe w background.slice o niskim CPUWeight i io.weight . Otrzymują one pełne zasoby, gdy system jest w stanie bezczynności, i ustępują miejsca, gdy pojawia się ruch produkcyjny.
W przypadku środowisk uruchomieniowych kontenerów, takich jak Docker i Podman, dodaj Delegate=yes do ich plików jednostek systemd. Pozwala to im zarządzać własnymi podgrupami cgroups bez uprawnień roota, a limity ustawione na nadrzędnym segmencie nadal mają zastosowanie do wszystkich elementów poniżej.
Monitorowanie za pomocą systemd-cgtop i PSI
Aby uzyskać podgląd na żywo w stylu top dotyczący procesora, pamięci i operacji wejścia/wyjścia dla poszczególnych grup cgroup, uruchom:
systemd-cgtop
Aby uzyskać statyczną hierarchię i informacje o tym, gdzie znajdują się poszczególne procesy, użyj systemd-cgls.
Najbardziej przydatną funkcją wersji 2 do monitorowania produkcji jest Pressure Stall Information (PSI). PSI podaje procent czasu, w którym zadania w cgroup były wstrzymane w oczekiwaniu na zasób, co jest widoczne w trzech plikach dla każdej cgroup:
cat /sys/fs/cgroup/tenant-a.slice/cpu.pressure
cat /sys/fs/cgroup/tenant-a.slice/memory.pressure
cat /sys/fs/cgroup/tenant-a.slice/io.pressure
Procesor o 100% wykorzystaniu i 0% presji działa prawidłowo. Każde zadanie, które potrzebuje procesora, otrzymuje go. Ten sam procesor o 80% wykorzystaniu, ale 30% presji oznacza, że zadania czekają w kolejce na czas działania. Należy monitorować PSI, a nie wykorzystanie: wykrywa ono konflikty, które wskaźniki wykorzystania całkowicie pomijają.
Dostosuj limity na żywo bez konieczności ponownego uruchamiania czegokolwiek:
sudo systemctl set-property tenant-a.slice MemoryMax=6144M
Zmiana obowiązuje natychmiast i jest zachowywana po ponownym uruchomieniu. W połączeniu z alertami opartymi na PSI pozwala to reagować na zmiany obciążenia, zanim przerodzą się one w zabijanie procesów z powodu braku pamięci (OOM) lub niekontrolowane opóźnienia.
Jeśli obsługujesz obciążenia wielodostępne o dużej gęstości i potrzebujesz hosta z wystarczającą rezerwą mocy, aby płynnie stosować te zasady, nasze serwery dedykowane są stworzone właśnie do tego.

Jak hostować modele Ollama AI na serwerach dedykowanych
Dowiedz się, jak hostować modele Ollama AI na serwerach dedykowanych, aby zapewnić bezpieczeństwo danych, skalowalność i zwiększyć wydajność.
5 min czytania - 8 września 2025
Jak zainstalować i korzystać z Redis na serwerze VPS
9 min czytania - 7 stycznia 2026

Masz pytania lub potrzebujesz niestandardowego rozwiązania?
Elastyczne opcje
Globalny zasięg
Natychmiastowe wdrożenie
Elastyczne opcje
Globalny zasięg
Natychmiastowe wdrożenie