Narzędzia nice, renice, ionice, taskset i trickle

Spis treści

W każdym systemie operacyjnym cała masa procesów rywalizuje ze sobą o zasoby, w skład których wchodzą min. pamięć operacyjna RAM, procesor i operacje I/O dysku twardego. Czasami zdarza się tak, że niektóre aplikacje są w stanie zdusić inne programy, bo mają zbyt duże wymagania co do zasobów systemowych. W takich przypadkach administrator systemu powinien zatroszczyć się o przydział zasobów konkretnym procesom. W linux'ie do tego typu prac przeznaczony jest mechanizm cgroups obecny w kernelu. Niemniej jednak, jeśli cgroups przerasta nasze umiejętności albo też z jakiegoś powodu nie możemy z niego korzystać, to istnieje inne rozwiązanie, które może nam pomóc ograniczyć zasoby przydzielane procesom przez nasz system. Chodzi generalnie o narzędzia nice/renice (procesor) , ionice (dysku twardy) , taskset (przypisanie procesu do konkretnego procesora) oraz trickle (sieć). W tym wpisie zobaczymy jak przy pomocy tych powyższych narzędzi limitować procesy systemowe.

Przydział procesora i dysku twardego (nice, renice, ionice)

Z reguły nice i ionice są wykorzystywane razem. Oczywiście, nic nie stoi na przeszkodzie, by korzystać z tych dwóch narzędzi osobno. Niemniej jednak, gdy w grę wchodzi ograniczanie zasobów procesom, to zwykle chcemy, by jeden z procesów miał niższy lub wyższy priorytet. A to z reguły prowadzi do ograniczenia przydziałów dwóch kluczowych urządzeń komputera, czyli procesora i dysku twardego. W przypadku ograniczenia tylko jednego z tych zasobów, proces w dalszym ciągu byłby w stanie korzystać z tego drugiego zasobu bez ograniczeń, co może czasami nie być pożądane. W przypadku korzystania zarówno z nice jak i ionice możemy tak skonfigurować proces, że jego operacje nie będą dla nas praktycznie w żaden sposób odczuwalne.

By korzystać z w/w narzędzi, musimy posiadać w swoim systemie odpowiednie pakiety. W przypadku debiana są to coreutils oraz util-linux . Raczej nie powinno być problemów z ich zainstalowaniem, zatem przejdźmy od razu do rzeczy, czyli ograniczenia zasobów procesora i dysku twardego.

Jeśli chcemy ograniczyć zasoby jakiemuś procesowi, przy jego wywoływaniu musimy dodać nice i/lub ionice . Każde z tych dwóch narzędzi może przyjąć też kilka opcji, przy pomocy których nadamy priorytet procesowi. W przypadku określenia zarówno nice jak i ionice stworzymy drzewo procesów, na końcu którego będzie nasza główna aplikacja. Całość działa na zasadzie dziedziczenia parametrów procesów. Przykładowo, jeśli proces z nice -n 19 wywoła inny proces, to ten drugi proces również dostanie z automatu nice -n 19 . Jest to dokładnie zobrazowane w htop na poniższym obrazu:

procesy-nice-htop-linux

Wyżej widzimy, że jednemu z paneli tint2 został przypisany nice -n -2 . Na tym panelu jest szereg aktywatorów aplikacji. Każdy uruchomiony proces z tego panelu będzie procesem potomnym i będzie dziedziczył parametry przydziału zasobów, tak jak to jest pokazane wyżej. Poniżej zaś jest przykładowe polecenie wywołania skryptu od backup'u:

# nice -n 19 ionice -c 3 backup.sh

Priorytety dla nice są z zakresu -20 do 19 . Zwykły użytkownik może nadawać tylko priorytety od 0 do 19 . Im wyższy numer tym niższy priorytet, czyli procesy z numerem -20 mają najwyższy priorytet, a te z numerem 19 najniższy.

W przypadku ionice , przy pomocy -c 3 ustalamy zapis/odczyt dysku na tryb IDLE , czyli gdy inne procesy aktualnie nie wykorzystują dysku. Możliwe jest także sprecyzowanie mniej agresywnego rozwiązania, czyli -c 2 -n 7 . Przy czym, opcja -n w tym przypadku jest z zakresu 0-7 i również im mniejsza wartość, tym wyższy priorytet, a im wyższy priorytet, tym lepszy dostęp do dysku.

Zmiana priorytetu procesu w locie

Warto też wiedzieć, że priorytet procesów w dostępie do procesora i dysku twardego można zmienić w czasie pracy takiego procesu. W przypadku zasobów procesora zamiast nice korzystamy z renice . Z kolei jeśli chodzi o dysk twardy, to procedura jest taka sama jak wyżej, czyli korzystamy z ionice . W obu przypadkach musimy korzystać z przełącznika -p , za pomocą którego wskazujemy numer procesu, którego priorytet chcemy zmienić. Poniżej są przykłady zmiany priorytetu procesu:

# renice -n 10 -p 1110
# ionice -c 2 -n 5 -p 1110

Z tymi powyższymi poleceniami jest tylko jeden problem. Co w przypadku drzewa procesów? Zmiana priorytetu jednemu procesowi nie stanowi problemu ale raczej nikomu się nie będzie chciało zmieniać szeregu procesów potomnych. Istnieje jednak sposób, który automatycznie dostosuje wszystkie te procesy potomne za nas. Musimy tylko poznać numer ID sesji procesów. To ID możemy poznać, np. przy pomocy ps lub htop (domyślnie nie jest pokazywane ID sesji i trzeba zaznaczyć odpowiednie opcje w konfiguracji). Poniżej jest przykład ps :

# ps -eo "user,group,sess,pid,args" | grep fire
morfik   morfik    44835  44835 /bin/sh -c /opt/firefox/firefox --new-instance --ProfileManager
morfik   morfik    44835  44836 /opt/firefox/firefox --new-instance --ProfileManager

Wartość 44835 to numer sesji. ID poszczególnych procesów przypisanych do tej sesji możemy ustalić w poniższy sposób:

# ps -eo sess:1=,pid:1=,nice:1= | grep 44835
44835 44835 0
44835 44836 0

Lub też przy pomocy pgrep . Poniżej przykład:

# pgrep -s 44835
44835
44836

By zmienić nice wszystkim procesom podpiętym do jednej sesji, wpisujemy w terminal to poniższe polecenie:

# renice -n 19 $(pgrep -s 44835)
44835 (process ID) old priority 0, new priority 19
44836 (process ID) old priority 0, new priority 19

Jak widać priorytety uległy zmianie. Podobnie postępujemy w przypadku ionice :

# ionice -c 3 -p $(pgrep -s 44835)

Jak przydzielić procesowi określony procesor/rdzeń (taskset)

Jeśli interesuje nas opcja, gdzie danym procesem zajmuje się określony rdzeń procesora, to możemy skorzystać z narzędzia taskset (zawarte w pakiecie util-linux ). W ten sposób na maszynie wielordzeniowej, konkretny proces będzie wykorzystywał tylko te rdzenie, do których zostanie przypisany. Wystarczy tylko, że określimy numer/numery rdzeni (numerowane od 0). I tak dla przykładu jeśli chcemy, by proces firefox'a działał na pierwszym, drugim, piątym i szóstym rdzeniu, to w terminalu wpisujemy poniższe polecenie:

# taskset -c 0,1,4,5 firefox

W przypadku, gdy chcemy zmienić przydział rdzeni procesora dla uruchomionego już procesu, musimy określić ID procesu. Poniżej przykład:

# taskset -a -p -c 1 82457
pid 15538's current affinity list: 0,1
pid 15538's new affinity list: 0

Za sprawą parametru -a wszystkie wątki powiązane z numerem PID procesu zostaną automatycznie przyporządkowane konkretnym rdzeniom.

Zmiana priorytetu procesów do zasobów sieciowych (trickle)

Narzędzie trickle (dostępne w pakiecie o tej samej nazwie) zajmuje się ograniczaniem pasma sieciowego dla danego procesu. Jednak trzeba uważać tutaj, by nie ustawić zbyt niskiej wartości. Jeśli taka sytuacja nam się przytrafi, to wtedy odpalany program zacznie sypać segfault'ami. Poniżej jest przykład nadania ograniczeń sieciowych przykładowemu procesowi:

# trickle -s -d 500 -u 100 qbittorrent

Za pomocą przełącznika -d określamy prędkość pobierania danych z internetu. Z kolei przy pomocy opcji -u definiujemy ograniczeniu upload'u. Obie wartości są w KiB/s

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.