Rodzaje procesów
Po tej lekcji: kursant rozróżnia procesy pierwszoplanowe, w tle, demony, procesy jądra i wątki, wie, czym jest PID 1, sieroty i zombie, i czyta stany R, S, D, T, Z w ps.
Wstęp
górna część top, czerwona ramka wokół słowa „zombie”
Tasks: 112 total, 1 running, 110 sleeping, 0 stopped, 1 zombieSzef zagląda Ci przez ramię: „ZOMBIE? Mamy wirusa? Dzwonię do działu bezpieczeństwa!”.
Spokojnie. Zombie w Linuksie to nie wirus i nie atak. To zwykła, codzienna rzecz, która czasem mówi Ci, że jakiś program jest napisany niechlujnie. Dziś zrobimy własnego zombie, na żywo, zobaczymy, czemu kill -9 go nie rusza, i jak się go naprawdę pozbywa. A po drodze poznasz całą załogę kuchni.
Pierwszy plan i tło
Zostajemy w restauracji. Kucharz może gotować przy Twoim stoliku, na Twoich oczach. Dopóki nie skończy, czekasz i nic innego nie zamówisz. To proces pierwszoplanowy.
sleep 5Przez pięć sekund terminal jest zajęty. Klawiatura należy do sleep.
Ale kucharz może też pójść na zaplecze. Robi swoje, a Ty w tym czasie zamawiasz dalej. To proces w tle. Wystarczy znak & na końcu:
sleep 5 &Terminal od razu jest wolny. Całe zarządzanie tym, co w tle, czyli jobs, fg, bg, Ctrl+Z, ma swój lekcja, czwarty od dziś. Dziś wystarczy, że wiesz: oba rodzaje mają terminal i oba są dziećmi Twojego Basha. Jak zamkniesz terminal, zwykle giną razem z nim.
Demony: nocna zmiana bez stolika
Są też kucharze, którzy w ogóle nie mają stolika. Pracują całą noc, nikt na nich nie patrzy, a jak przychodzi zamówienie przez okienko, po prostu je realizują. To demony, po angielsku daemon.
Demon to proces, który działa w tle, nie ma terminala i zwykle czeka na coś: na połączenie, na godzinę, na plik. Po nazwie często go poznasz, bo kończy się na „d”:
sshd— czeka na połączenia SSH,systemd-journald— zbiera logi,crondna RHEL icronna Ubuntu — budzik, uruchamia zadania o czasie,httpdna RHEL iapache2na Ubuntu — serwer WWW, ta sama recepcja hotelu pod dwiema nazwami,chronyd— pilnuje zegara.
A jeden demon już znasz. Pamiętasz, czemu sesja tmux przeżyła rozłączenie?
ps -o pid,ppid,sid,tty,stat,comm -p $(pgrep -f "tmux: server") PID PPID SID TT STAT COMMAND
3536 1 3536 ? Ss tmux: serverSerwer tmux to klasyczny demon. Rodzic: proces numer 1. Terminal: znak zapytania, czyli żaden. W STAT ma małe s, czyli jest liderem własnej sesji, odcięty od Twojego okna. Dlatego zamknięcie terminala go nie obchodzi. Twoje okno to był tylko stolik, przy którym na chwilę usiadłeś.
[Ubuntu] [RHEL] Na obu rodzinach demonami zarządza systemd. To on je uruchamia, pilnuje i wstaje do nich w nocy. Szczegóły w lekcji o usługach.
Procesy jądra: obsługa techniczna
W ps aux widziałeś nazwy w nawiasach kwadratowych. To wątki jądra. Nie są programami z dysku, tylko kawałkami samego jądra, które robią robotę w tle: zapisują dane na dysk, sprzątają pamięć, obsługują przerwania. Elektryk i hydraulik budynku. Nie gotują, ale bez nich kuchnia stanie.
ps -o pid,ppid,stat,cmd -p 2,3,15
ps --ppid 2 -o pid,comm | head -4 PID PPID STAT CMD
2 0 S [kthreadd]
3 2 S [pool_workqueue_release]
15 2 R [rcu_preempt]
PID COMMAND
3 pool_workqueue_release
4 kworker/R-rcu_gp
5 kworker/R-sync_wqSzefem obsługi jest kthreadd z numerem 2. Jego rodzic to zero, bo uruchamia go samo jądro. Wszystkie inne wątki jądra są jego dziećmi, mają PPID 2. Nazwy, które zobaczysz najczęściej: kworker (złota rączka do wszystkiego), ksoftirqd (kończenie obsługi przerwań), kswapd0 (przenoszenie pamięci do swapa). Jeśli kswapd0 zjada procesor, to nie jego wina. To znak, że brakuje RAM-u.
I ważne: tych procesów nie zabijasz. Nie da się, nie trzeba, nie próbuj. To jak wyrzucenie hydraulika w trakcie wymiany rury.
Wątki: kucharz z kilkoma parami rąk
Proces może mieć kilka wątków. To jak kucharz, któremu wyrosły dodatkowe ręce: jedna miesza zupę, druga kroi cebulę, trzecia odbiera telefon. Wszystkie ręce dzielą ten sam stół, te same garnki i ten sam PID. Różnią się tylko tym, co akurat robią.
python3 -c "import threading,time; [threading.Thread(target=time.sleep,args=(300,)).start() for _ in range(3)]; time.sleep(300)" &
ps -o pid,nlwp,cmd -p $!
ps -T -p $! PID NLWP CMD
8557 4 python3 -c import threading,time; [threading.Thread(...
PID SPID TTY TIME CMD
8557 8557 pts/3 00:00:00 python3
8557 8559 pts/3 00:00:00 python3
8557 8560 pts/3 00:00:00 python3
8557 8561 pts/3 00:00:00 python3Jeden program w Pythonie, który odpala trzy wątki. NLWP mówi: cztery wątki, czyli główny plus trzy dodatkowe. ps -T pokazuje każdy osobno: PID ten sam, ale każdy wątek ma własny numer w kolumnie SPID. Bazy danych, przeglądarki i serwery aplikacji mają tych rąk dziesiątki albo setki.
PID 1: kierownik zmiany
Proces numer 1 na Ubuntu i RHEL to systemd. Kierownik zmiany. Uruchamia całą resztę i ma dwa obowiązki, o których mało kto wie.
Pierwszy: adoptuje sieroty. Za chwilę zobaczysz, co to znaczy.
Drugi: zamyka rachunki po zmarłych. O tym za dwie chwile.
A do tego jest chroniony. Jądro dostarcza procesowi numer 1 tylko te sygnały, na które on sam zgłosił obsługę. Chodzi o to, żeby nikt nie położył całego systemu jedną literówką. Gdyby PID 1 jednak zginął, jądro wpada w panikę i system staje. Kierownik zmiany wyszedł, zamykamy restaurację.
Sieroty: kucharz bez szefa
Co się dzieje, kiedy rodzic kończy pracę, a dziecko jeszcze gotuje?
bash -c 'sleep 500 & echo "dziecko: $!"'
ps -o pid,ppid,stat,cmd -p 6675dziecko: 6675
PID PPID STAT CMD
6675 1 S sleep 500Bash uruchomił sleep 500 w tle, wypisał numer dziecka i od razu się zakończył. sleep został sierotą. Ale nie błąka się po kuchni bez opieki. Jądro natychmiast przepisało go pod proces numer 1. PPID zmienił się na 1. Kierownik zmiany adoptuje każdego.
I to jest w porządku. Sierota to nie błąd, tylko normalna sytuacja. Tak zresztą powstają demony: celowo zostawiają rodzica i przechodzą pod kierownika.
Zombie: niezamknięty rachunek
Teraz gwiazda lekcji.
Gość zjadł, zapłacił i wyszedł. Ale kelner nie zamknął rachunku w kasie. Na sali nikogo już nie ma, a w systemie dalej wisi otwarty stolik numer 7. To jest zombie.
Po ludzku: proces dziecko się zakończył. Jądro zabrało mu już pamięć i pliki. Zostawiło tylko maleńką kartkę z numerem i kodem wyjścia, czyli informacją, jak poszło: kciuk w górę czy w dół. Ta kartka czeka, aż rodzic ją odbierze. Jeśli rodzic jej nigdy nie odbierze, kartka wisi. Proces nie żyje, ale wciąż jest na liście. Żywy trup. Stąd nazwa.
Zróbmy własnego:
bash -c 'sleep 1 & exec sleep 300' &
sleep 2
ps -o pid,ppid,stat,cmd --ppid $!
ps -o pid,ppid,stat,cmd -p $![1] 6425
PID PPID STAT CMD
6426 6425 Z [sleep] <defunct>
PID PPID STAT CMD
6425 4900 S sleep 300Co tu się stało? Bash uruchomił dziecko sleep 1 w tle, a potem przez exec zamienił się w sleep 300. Pamiętasz exec z poprzedniej lekcji? Ten sam PID, inny program. A sleep w ogóle nie wie, że ma jakieś dziecko, więc nigdy nie odbiera rachunku. Po sekundzie sleep 1 kończy pracę i staje się zombie: stan Z, nazwa w nawiasach i dopisek <defunct>, czyli „nieżyjący”.
To jest właśnie niechlujny rodzic. W prawdziwym życiu to zwykle aplikacja z błędem, która uruchamia procesy pomocnicze i o nich zapomina.
To co, zabijamy?
kill -9 6426
ps -o pid,ppid,stat,cmd -p 6426 PID PPID STAT CMD
6426 6425 Z [sleep] <defunct>Nic. Najmocniejszy sygnał w systemie i zero efektu. Bo nie da się zabić kogoś, kto już nie żyje. To jak dzwonienie do gościa, żeby wyszedł z restauracji, kiedy jest już w domu. Problem nie siedzi w zombie, tylko w rodzicu.
Więc kończymy rodzica:
kill 6425
sleep 2
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'
echo "zombie: $(ps -eo stat= | grep -c Z)"zombie: 0Rodzic znika, zombie zostaje sierotą, kierownik zmiany go adoptuje i od razu zamyka rachunek. Czysto.
Czy zombie są groźne? Jeden, dwa, nawet dziesięć: nie. Nie zjadają procesora ani pamięci. Zajmują tylko miejsce w tabeli procesów, czyli numer PID. Ale jeśli liczba zombie rośnie z godziny na godzinę, kiedyś skończą się numery i system nie uruchomi żadnego nowego procesu. Wtedy szukasz rodzica i zgłaszasz błąd jego twórcom, a na razie restartujesz rodzica.
Stany procesu: co kucharz teraz robi
Kolumna STAT w ps i S w top to stan. Pierwsza litera jest najważniejsza:
- R — running. Kucharz stoi przy kuchence albo czeka w kolejce, żeby do niej podejść. Oba przypadki to
R. - S — sleeping. Śpi i czeka na coś: na dostawę, na klienta, na dane z sieci. Obudzi się na dzwonek. Tak wygląda większość procesów w systemie, prawie przez cały czas.
- D — uninterruptible sleep, sen nieprzerywalny. Kucharz czeka na dostawę, której nie wolno przerwać. Nie reaguje na nic, nawet na
kill -9. Zwykle czeka na dysk albo na dysk sieciowy, na przykład NFS. Na moment to normalne. Ale wiele procesów wiszących długo wDto znak, że dysk albo sieć do dysku umierają. I to właśnieDczęsto podbija obciążenie systemu, które poznasz w następnej lekcji. - T — stopped. Zatrzymany, zamrożony w pół ruchu. Tak działa Ctrl+Z albo sygnał
STOP. - Z — zombie. Już znasz.
- I — idle, bezczynny wątek jądra. Widzisz go tylko przy procesach w nawiasach.
Zamrażanie na żywo:
sleep 900 &
kill -STOP $!
ps -o pid,stat,cmd -p $!
kill -CONT $!
ps -o pid,stat,cmd -p $! PID STAT CMD
9044 T sleep 900
PID STAT CMD
9044 S sleep 900Po STOP stan T. Po CONT, czyli „continue”, wraca do S. Jak gra w „Raz, dwa, trzy, Baba Jaga patrzy”.
Po pierwszej literze w ps aux bywają dodatkowe znaczki:
s— lider sesji, zwykle powłoka albo demon,+— proces na pierwszym planie w swoim terminalu,l— ma wiele wątków,<— wysoki priorytet,N— niski. O priorytetach będzie osobna lekcja.
Cały system w jednym rankingu:
ps -eo stat= | cut -c1 | sort | uniq -c | sort -rn 72 S
36 I
1 RTrójka sort | uniq -c | sort -rn z lekcji 7 znowu w akcji. Prawie wszyscy śpią, jeden pracuje. I ten jeden to najczęściej sam ps, który akurat robi zdjęcie.
Jak to działa pod spodem
Kiedy proces się kończy, wywołuje exit z kodem wyjścia. Jądro sprząta jego pamięć i pliki, ale zostawia w tabeli procesów wpis z kodem. Potem wysyła rodzicowi sygnał SIGCHLD: „Twoje dziecko skończyło”. Rodzic powinien wtedy wywołać wait, odebrać kod i dopiero wtedy wpis znika.
I tu ciekawostka: Bash robi to za każdym razem, kiedy uruchamiasz komendę. Czeka na dziecko, odbiera jego kod i wkłada go do $?. Kciuk w górę albo w dół, który sprawdzasz po każdej komendzie, to dosłownie zawartość tej kartki po zombie. Bash jest wzorowym kelnerem.
A jeśli rodzic umiera pierwszy, jądro przepisuje jego dzieci pod proces numer 1, który automatycznie wywołuje wait i sprząta. To wszystko jest opisane w man 2 wait.
Ściąga flag
| Komenda | Flaga | Co robi |
|---|---|---|
ps | -o stat | stan procesu (R, S, D, T, Z, I) |
ps | --ppid PID | dzieci danego procesu |
ps | -T -p PID | wątki jednego procesu |
ps | -eLf | wszystkie wątki w systemie |
ps | -o nlwp | liczba wątków procesu |
ps | -o ppid= -p PID | sam numer rodzica, bez nagłówka |
pgrep | -r Z | procesy w danym stanie, np. zombie |
kill | -STOP PID | zamraża proces (stan T) |
kill | -CONT PID | odmraża proces |
top | linia Tasks | ile procesów w którym stanie, w tym zombie |
pstree | -p | kto jest czyim rodzicem |
⚠ Typowy błąd
Monitoring krzyczy: „3 zombie”. Admin robi:
kill -9 $(pgrep -r Z)I nic. Robi to jeszcze raz, z sudo. Dalej nic. Potem pisze na forum, że Linux jest zepsuty.
Zombie nie da się zabić, bo już nie żyje. Trzeba znaleźć rodzica:
pgrep -r Z -a
ps -o ppid= -p 3104831048 [sleep] <defunct>
31045Drugi numer to rodzic. Ten jest winny. Sprawdzasz, co to za program, i robisz mu grzeczny restart. Najlepiej przez systemd, jeśli to usługa, bo wtedy wstanie z powrotem. Po restarcie rodzica zombie znikają, bo przejmuje je i sprząta proces numer 1. A jeśli rodzicem jest PID 1 i zombie wiszą długo, to masz poważniejszy problem i to temat na zgłoszenie, nie na kill.
✎ Zadanie
- Zrób własnego zombie komendą z tej lekcji.
- Znajdź go przez
pspo stanieZi sprawdź, kto jest jego rodzicem. - Spróbuj zabić zombie przez
kill -9i sprawdź, że dalej jest. - Posprzątaj go, kończąc rodzica, i sprawdź, że zombie zniknął.
- Na koniec policz jedną linijką, ile procesów w Twoim systemie jest w każdym stanie.
Pokaż rozwiązanie
bash -c 'sleep 1 & exec sleep 300' &
sleep 2
ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'
kill -9 6426
ps -o pid,ppid,stat,cmd -p 6426
kill 6425
ps -eo stat= | cut -c1 | sort | uniq -c | sort -rn 6426 6425 Z [sleep] <defunct>
PID PPID STAT CMD
6426 6425 Z [sleep] <defunct>
72 S
36 I
1 RZombie w stanie Z, rodzic w kolumnie PPID. Po kill -9 zombie dalej leży, bo trudno zabić kogoś dwa razy. Po zakończeniu rodzica zombie znika, bo sprząta go kierownik zmiany. Jeśli Twój zombie przetrwał i to, to gratuluję, masz materiał na horror. Albo pomyliłeś PID-y, co jest dużo bardziej prawdopodobne.
Co dalej
ps robi zdjęcie. W następnej lekcji włączamy film: top. Rozszyfrujemy cały ten ekran od góry do dołu, łącznie z tajemniczym load average, które wszyscy cytują, a mało kto wie, co znaczy.