Jak korzystać z cgroups, aby ograniczyć wszystkie procesy oprócz białej listy do jednego procesora?

26

Istnieje przewodnik dla grup z Red Hat, który może jest swego rodzaju pomocny (ale nie odpowiada na to pytanie).

Wiem, jak ograniczyć konkretny proces do określonego procesora podczas polecenia uruchomienia tego procesu przez:

Najpierw wstaw następujące * /etc/cgconfig.conf:

mount {
  cpuset =  /cgroup/cpuset;
  cpu =     /cgroup/cpu;
  cpuacct = /cgroup/cpuacct;
  memory =  /cgroup/memory;
  devices = /cgroup/devices;
  freezer = /cgroup/freezer;
  net_cls = /cgroup/net_cls;
  blkio =   /cgroup/blkio;
}

group cpu0only {
  cpuset {
    cpuset.cpus = 0;
    cpuset.mems = 0;
  }
}

A następnie uruchom proces i przypisz go konkretnie do tej grupy, używając:

cgexec -g cpuset:cpu0only myprocessname

Mogę automatycznie ograniczyć wszystkie wystąpienia określonej nazwy procesu, (myślę, że jest to poprawne), umieszczając następujące elementy /etc/cgrules.conf:

# user:process  controller  destination
*:myprocessname cpuset      cpu0only

Moje pytanie brzmi: jak mogę zrobić odwrotnie ?

Innymi słowy, jak mogę przypisać wszystkie procesy oprócz określonego zestawu procesów z białej listy i ich dzieci do ograniczonej grupy?


Na podstawie tego, co studiowałem, ale nie testowałem, uważam , że rozwiązaniem częściowym byłoby:

Dodaj grupę „nieograniczoną”:

group anycpu {
  cpuset {
    cpuset.cpus = 0-31;
    cpuset.mems = 0;  # Not sure about this param but it seems to be required
  }
}

Przydziel mój proces jawnie grupie nieograniczonej, a wszystko inne grupie ograniczonej:

# user:process  controller  destination
*:myprocessname cpuset      anycpu
*               cpuset      cpu0only

Jednak wydaje się, że jest to zastrzeżenie (z czytania dokumentacji, a nie z testowania, więc ziarna soli), że dzieci myprocessnamezostaną przeniesione do ograniczonej cpu0onlygrupy.

Możliwe alternatywne podejście polegałoby na stworzeniu użytkownika, który będzie działał myprocessnamei będzie miał nieograniczone wszystkie procesy tego użytkownika , a wszystko inne ograniczone. Jednak w moim przypadku użycia proces musi być uruchamiany przez root, a istnieją inne procesy, które również muszą być uruchamiane przez root, które powinny być ograniczone.

Jak mogę to osiągnąć za pomocą cgroups?


Jeśli nie jest to możliwe w przypadku grup dyskusyjnych (co teraz podejrzewam, że tak jest), czy moje pomysły na częściowe rozwiązania są prawidłowe i czy będą działać tak, jak myślę?

* Oświadczenie: Prawdopodobnie nie jest to minimalny przykład kodu; nie rozumiem wszystkich części, więc nie wiem, które nie są konieczne.

Dzika karta
źródło

Odpowiedzi:

30

AKTUALIZACJA: Zauważ, że odpowiedź poniżej dotyczy RHEL 6. W RHEL 7 większość grup jest zarządzana przez systemd, a libcgroup jest przestarzała.


Od czasu opublikowania tego pytania przestudiowałem cały przewodnik, do którego odsyłam , a także większość dokumentacji cgroups.txt i cpusets.txt . Teraz wiem więcej, niż się spodziewałem, aby dowiedzieć się o grupach, więc tutaj odpowiem na własne pytanie.

Istnieje wiele metod, które możesz zastosować. Kontakt z naszą firmą w Red Hat (architekt techniczny) zalecił całkowite ograniczenie wszystkich procesów zamiast bardziej deklaratywnego podejścia - ograniczając tylko te procesy, które konkretnie chcieliśmy ograniczyć. Powodem tego, zgodnie z jego wypowiedziami na ten temat, jest to, że wywołania systemowe mogą zależeć od kodu przestrzeni użytkownika (takiego jak procesy LVM), który w przypadku ograniczenia może spowolnić system - odwrotnie niż zamierzony efekt. Skończyłem więc na ograniczeniu kilku specjalnie nazwanych procesów i pozostawieniu wszystkiego innego w spokoju.

Ponadto chcę wspomnieć o niektórych podstawowych danych grupy , których brakowało, kiedy opublikowałem swoje pytanie.


Grupy C nie zależą od libcgroupinstalacji. Jest to jednak zestaw narzędzi do automatycznej obsługi konfiguracji cgroup i przypisywania procesów do cgroups i może być bardzo pomocny.

Odkryłem, że narzędzia libcgroup mogą również wprowadzać w błąd, ponieważ pakiet libcgroup jest zbudowany na własnym zestawie abstrakcji i założeń dotyczących korzystania z cgroups, które nieco różnią się od faktycznej implementacji cgroups na poziomie jądra. (Mogę podać przykłady, ale zajęłoby to trochę pracy; skomentuj, jeśli jesteś zainteresowany.)

Dlatego przed użyciem narzędzia libcgroup (takich jak /etc/cgconfig.conf, /etc/cgrules.conf, cgexec, cgcreate, cgclassify, itd.) Ja bardzo polecam się bardzo znane z /cgroupsamego wirtualnego systemu plików i ręcznego tworzenia cgroups, hierarchie cgroup (w tym hierarchii z wielu podsystemów przyłączone, który libcgroup podstępnie i leakily streszczeń od siebie), przypisywanie procesów do różnych grup przez uruchamianie echo $the_pid > /cgroup/some_cgroup_hierarchy/a_cgroup_within_that_hierarchy/tasksi inne pozornie magiczne zadania, które libcgroupwykonuje się pod maską.


Kolejna podstawowa koncepcja mi brakuje, że jeśli /cgroupwirtualny system plików jest zamontowany w systemie w ogóle (lub dokładniej, jeśli któryś z podsystemów cgroup aka „kontrolerów” są zamontowane w ogóle), a następnie każdy proces na cały system jest w A grupa. Nie ma czegoś takiego jak „niektóre procesy są w grupie, a niektóre nie”.

Istnieje tak zwana grupa główna dla danej hierarchii, która jest właścicielem wszystkich zasobów systemu dla dołączonych podsystemów. Na przykład hierarchia grupy cg, do której dołączone są podsystemy cpuset i blkio, miałaby główną grupę cg, która byłaby właścicielem całego cpus w systemie i całego blkio w systemie, i mogłaby współdzielić niektóre z tych zasobów z podrzędnymi grupami cgroup . Nie możesz ograniczyć grupy root, ponieważ posiada ona wszystkie zasoby systemu, więc ograniczenie nie miałoby nawet sensu.


Kilka innych prostych danych, których mi brakowało na temat libcgroup:

Jeśli używasz /etc/cgconfig.conf, powinieneś upewnić się, że chkconfig --list cgconfigpokazy cgconfigsą ustawione na uruchomienie systemu.

Jeśli zmienisz /etc/cgconfig.conf, musisz uruchomić, service cgconfig restartaby załadować zmiany. (A problemy z zatrzymaniem usługi lub uruchomieniem cgclearsą bardzo częste podczas wygłupów podczas testowania. Do debugowania zalecam na przykład lsof /cgroup/cpuset, jeśli cpusetjest to nazwa używanej hierarchii grupy).

Jeśli chcesz użyć /etc/cgrules.conf, musisz upewnić się, że działa „demon silnika reguł cgroup” ( cgrulesengd): service cgred starti chkconfig cgred on. (I powinieneś zdawać sobie sprawę z możliwego, ale mało prawdopodobnego stanu wyścigu dotyczącego tej usługi, jak opisano w Przewodniku zarządzania zasobami Red Hat w sekcji 2.8.1 na dole strony).

Jeśli chcesz oszukiwać ręcznie i konfigurować grupy za pomocą wirtualnego systemu plików (który zalecam do pierwszego użycia), możesz to zrobić, a następnie utworzyć cgconfig.confplik, aby odzwierciedlić konfigurację za pomocą cgsnapshotróżnych opcji.


I na koniec kluczowa informacja, której mi brakowało, kiedy napisałem:

Jednak zastrzeżenie w tej sprawie wydaje się ... że dzieci z myprocessname zostaną ponownie przypisane do ograniczonej grupy cpu0only.

Miałem rację, ale jest opcja, o której nie wiedziałam.

cgexec to polecenie, aby rozpocząć proces / uruchomić polecenie i przypisać je do grupy.

cgclassify to polecenie przypisujące już działający proces do grupy.

Obie te będą również zapobiegać cgred( cgrulesengd) z realokacja określonego procesu do innego cgroup na bazie /etc/cgrules.conf.

Zarówno cgexeci cgclassifywspierać --stickyflagę, która dodatkowo zapobiega cgredod realokacja potomnych procesów w oparciu o /etc/cgrules.conf.


Tak więc odpowiedź na pytanie, które napisałem (choć nie konfigurację, którą ostatecznie wdrożyłem, z powodu porady naszego architekta technicznego Red Hat wspomnianego powyżej) brzmi:

Utwórz grupy cpu0onlyi anycpucgroup zgodnie z opisem w moim pytaniu. (Upewnij się, że cgconfigjest ustawiony do uruchamiania podczas rozruchu).

Ustaw * cpuset cpu0onlyregułę zgodnie z opisem w moim pytaniu. (I upewnij się, że cgredjest ustawiony do uruchamiania podczas rozruchu).

Zacznij żadnych procesów chcę, nieograniczony z: cgexec -g cpuset:anycpu --sticky myprocessname.

Procesy te będą nieograniczone, a wszystkie ich procesy potomne również będą nieograniczone. Cała reszta w systemie będzie ograniczona do CPU 0 (po ponownym uruchomieniu, ponieważ cgrednie stosuje cgrules do już działających procesów, chyba że zmienią swój identyfikator EUID). Nie jest to całkowicie wskazane, ale tego właśnie początkowo zażądałem i można to zrobić za pomocą cgroups.

Dzika karta
źródło
łał. fajne. jak to miało 0 głosów?
mikeserv
@mikeserv, dzięki. :) Odpowiedz na pytanie: sprawdź daty; Właśnie napisałem tę odpowiedź wczoraj.
Wildcard
1
widziałem to. ale to było 24 godziny temu. prawdopodobnie jego przyczyna jest długa. dobre rzeczy mogą czasem zostać przeoczone w ten sposób. w każdym razie odpowiedzi z dużą ilością głosów naprawdę bardzo rzadko są dobre - informacje nie mogą być przydatne, jeśli tak wiele osób już o tym wie. jest to jednak jeden z dobrych. grupy są cholernie tajemnicze.
mikeserv