Tarkibga o'tish

Signallar va jarayonlarni boshqarish: kill, SIGTERM va SIGKILL

Jarayon ustuvorligini pasaytirish yoki oshirish u qancha CPU vaqti olishini o'zgartiradi, lekin jarayonni hech qachon to'xtatmaydi — ustuvorligi pasaytirilgan jarayon cheksiz ishlashda davom etadi. Administratorlarga esa muntazam ravishda butunlay boshqacha narsa kerak bo'ladi: qotib qolgan jarayonni majburan tugatish, ishlab turgan xizmatga to'liq qayta ishga tushirmasdan konfiguratsiyasini qayta yuklashni buyurish yoki uzoq davom etadigan ishni pauza qilib, keyinroq davom ettirish. Uchalasi ham bitta kernel mexanizmi — signallar orqali bajariladi, garchi ular uchun kundalik buyruqlar (kill, killall, Ctrl+C) tashqaridan bir-biriga bog'liq bo'lmagandek ko'rinsa ham.

Bu maqolada signal kernel darajasida aslida nima ekanini, kundalik administratorlik uchun muhim bo'lgan bir nechta signalni, nega SIGKILL birinchi refleks emas, oxirgi chora ekanini va jarayon signaldan shunchaki o'lish o'rniga uni qanday ushlab, qayta ishlashi mumkinligini ko'rib chiqamiz.

Signal aslida nima

Signal — kernel jarayonga yetkazadigan cheklangan, asinxron bildirishnoma. U kichik butun son va ramziy nom bilan aniqlanadi (SIGTERM — 15-signal, SIGKILL — 9-signal). Signallar jarayon hozir bajarayotgan ishni uzib qo'yadi va uni bildirishnomani uchta mumkin bo'lgan munosabatdan (disposition) biriga ko'ra qayta ishlashga majbur qiladi:

  • Standart amal — agar jarayon hech qanday maxsus ish qilmasa, ko'pchilik signallar uchun kernel belgilagan standart amal bor: tugatish, core dump bilan tugatish, to'xtatish, davom ettirish yoki (ba’zilari uchun) butunlay e’tiborsiz qoldirish.
  • E’tiborsiz qoldirilgan — jarayon kernelga signalni e’tiborga olmaslikni aniq aytishi mumkin.
  • Ushlangan (qayta ishlangan) — jarayon signal kelganda ishga tushadigan o'z funksiyasini ro'yxatdan o'tkazishi mumkin. Bu unga qanday davom etishni hal qilishdan oldin resurslarni tozalash, hodisani logga yozish yoki konfiguratsiyani qayta yuklash imkonini beradi.

Eng muhimi, har bir signalni ushlash yoki e’tiborsiz qoldirish mumkin emas. SIGKILL (9) va SIGSTOP (19) ni kernel to'g'ridan-to'g'ri qayta ishlaydi va nishondagi jarayon ularni hech qanday sharoitda ushlay, bloklay yoki ularga o'z ishlovchisini bera olmaydi. Bu jarayon qanchalik yomon ishlamasin, uni to'xtatish yoki tugatishning har doim yo'li bo'lishini ta’minlaydigan ataylab qilingan loyiha kafolati.

Kundalik ishda muhim signallar

Signal Raqami Standart amali Odatiy qo'llanishi
SIGHUP 1 tugatish tarixan "terminal aloqasi uzildi"; daemon’lar uni ko'pincha "konfiguratsiyani qayta yukla" ma’nosida ishlatadi
SIGINT 2 tugatish interaktiv terminalda Ctrl+C yuboradi
SIGQUIT 3 tugatish + core dump Ctrl+\ yuboradi; nosozliklarni tuzatish uchun core dump so'raydi
SIGKILL 9 tugatish shartsiz, ushlab bo'lmaydigan tugatish
SIGTERM 15 tugatish muloyim, ushlanadigan to'xtash so'rovi — kill sukut bo'yicha yuboradigan signal
SIGSTOP 19 to'xtatish shartsiz, ushlab bo'lmaydigan pauza
SIGCONT 18 davom ettirish to'xtatilgan jarayonni davom ettiradi
SIGTSTP 20 to'xtatish Ctrl+Z yuboradi; SIGSTOP dan farqli ravishda ushlanadi
SIGCHLD 17 e’tiborsiz qoldiriladi bola jarayon tugaganda yoki to'xtaganda ota jarayonga yuboriladi
SIGUSR1/SIGUSR2 10/12 tugatish ilovaning o'z maxsus ma’nosi uchun ajratilgan

Aniq signal raqamlari CPU arxitekturasiga qarab biroz farq qilishi mumkin, lekin yuqorida keltirilganlari Ubuntu Server va RHEL oilasidagi tizimlarda ishlatiladigan keng tarqalgan x86_64 va aarch64 platformalarida bir xil.

Signal yuborish: kill, killall, pkill

Nomiga qaramay, kill faqat tugatish signallarini emas, istalgan signalni yuboradi — bu nom tarixan uning eng ko'p qo'llanishi tugatish bo'lganini aks ettiradi.

kill -TERM 22110
kill -SIGTERM 22110
kill -15 22110

Uchala qator ham bir xil; kill signalni ramziy nomi bo'yicha (SIG prefiksi bilan yoki usiz) yoki raqami bo'yicha qabul qiladi. Hech qanday signal ko'rsatilmasa, kill 22110 sukut bo'yicha SIGTERM yuboradi.

killall nginx
pkill -f 'backup-script.sh'

killall jarayonning aniq nomi bo'yicha moslaydi; pkill esa nom bo'yicha yoki -f bilan butun buyruq qatoriga nisbatan moslaydi. Bu moslashuvchanroq, lekin ko'zda tutilmagan narsaga mos kelish ehtimoli ham yuqoriroq.

Warning

Andoza bo'yicha signal yuborishdan oldin nishonni doim tasdiqlang. Avval pgrep -af '<pattern>' ni (yoki killall ning aniq nom bo'yicha moslashi uchun pgrep -a ni) bajaring va mos kelgan natijaning har bir qatorini o'qing — ko'zda tutilganidan kengroq andoza nomi yoki argumentlarida shunchaki xuddi shu satr bo'lgan, umuman bog'liq bo'lmagan jarayonni tugatib yuborishi mumkin.

Jarayonga signal yubormasdan uning mavjudligini tekshirish

kill -0 22110
echo $?

0-signal maxsus: kernel hech qanday signalni aslida yetkazmasdan, mavjudlik va ruxsat tekshiruvini bajaradi. 0 chiqish holati jarayon mavjudligini va sizda unga signal yuborish ruxsati borligini bildiradi; noldan farqli holat ("No such process" kabi xabar bilan) esa jarayon mavjud emasligini yoki sizda ruxsat yo'qligini bildiradi. Bu skriptda "bu PID hali tirikmi" degan savolni tekshirishning standart, yon ta’sirsiz usuli.

SIGTERM va SIGKILL: nega tartib muhim

SIGTERM jarayondan to'xtashni so'raydi. U ushlanishi mumkin bo'lgani uchun to'g'ri yozilgan jarayon undan chiqishdan oldin ochiq fayllarni yopish, buferdagi yozuvlarni diskka yozish, bajarilayotgan ma’lumotlar bazasi tranzaksiyasini tugatish va qulflarni toza bo'shatish uchun ishora sifatida foydalanadi. SIGKILL esa jarayonga bunday imkon bermaydi — kernel uni keyingi rejalashtirish imkoniyatidayoq, hech qanday tozalash kodi ishlamasdan darhol tugatadi.

kill -TERM 22110
sleep 5
kill -0 22110 && kill -KILL 22110

Bu standart bosqichma-bosqich kuchaytirish andozasi: muloyim to'xtashni so'rang, jarayon haqiqatan chiqishi uchun oqilona vaqt kuting va faqat shu imtiyozli muddatdan keyin ham tirik bo'lsa, SIGKILL yuboring. systemctl stop ichida aynan shu andozaga amal qiladi va uni har bir unit uchun TimeoutStopSec orqali sozlash mumkin.

Danger

SIGKILL (kill -9) ga birinchi refleks sifatida murojaat qilish muntazam ravishda haqiqiy zarar keltiradi: yozish o'rtasida o'ldirilgan ma’lumotlar bazasi jarayoni keyingi ishga tushishda sekin tiklashni talab qiladigan buzilgan ma’lumotlar faylini qoldirishi mumkin; taqsimlangan qulfni ushlab turgan ilova uni hech qachon bo'shatmaydi, chunki uning tozalash ishlovchisi umuman ishlamaydi; jarayon muloyim chiqishda o'chirgan bo'ladigan vaqtinchalik fayl qolib ketadi. Har doim avval SIGTERM ni sinab ko'ring va kuchaytirishdan oldin jarayonga o'zi chiqib ketishi uchun haqiqiy imkoniyat bering.

Qayta ishga tushirmasdan konfiguratsiyani qayta yuklash: SIGHUP

Ko'p uzoq ishlaydigan daemon’lar — nginx, sshd, rsyslog — SIGHUP ni (uning asl, terminal bilan bog'liq standart amali jarayonni shunchaki tugatardi) mavjud ulanishlarni uzmasdan yoki to'plangan holatni yo'qotmasdan, konfiguratsiya faylini joyida qayta yuklash so'rovi sifatida qayta ma’nolaydi:

sudo nginx -t
sudo kill -HUP "$(cat /run/nginx.pid)"

nginx -t signal yuborishdan oldin konfiguratsiya sintaksisini tekshiradi. Ilovaga qarab, buzilgan konfiguratsiya fayli bilan SIGHUP yuborish jarayonni nomuvofiq holatda qoldirishi yoki qayta yuklash jimgina muvaffaqiyatsiz bo'lishiga olib kelishi mumkin. Qaysi daemon bo'lishidan qat’i nazar, avval tekshirish xavfsizroq odat.

systemctl reload <service> odatda aynan shu SIGHUP mexanizmi (yoki unit faylining ExecReload= qismida sozlangan ilovaga xos ekvivalent) ustidagi yupqa va topilishi osonroq o'rama. Xizmat systemd tomonidan boshqarilsa, signalni qo'lda yuborishdan ko'ra undan foydalanish afzal — u systemd’ning unit holati haqidagi o'z tasavvurini izchil saqlaydi.

Pauza qilish va davom ettirish: SIGSTOP va SIGCONT

kill -STOP 22110
ps -o pid,stat,cmd -p 22110
kill -CONT 22110
    PID STAT CMD
  22110 T    /usr/local/bin/long-running-job

T STAT i jarayon haqiqatan to'xtatilganini tasdiqlaydi — u ishlamayapti ham, uxlamayapti ham, shunchaki kernel tomonidan joyida muzlatib qo'yilgan: CPU vaqtini sarflamaydi, lekin barcha xotirasi va ochiq fayl deskriptorlarini saqlab turadi. SIGCONT uni aynan to'xtagan joyidan davom ettiradi. Bu juftlik ba’zan resurs talab qiladigan fon ishini raqobat davrida vaqtincha pauza qilish uchun foydali — uni tugatib, qayta ishga tushirishdagi kabi uning bajargan ishi yo'qolmaydi.

Jarayon signalni qanday ushlaydi

Ilova sigaction() (yoki eskiroq signal()) system call’i orqali signal ishlovchisini ro'yxatdan o'tkazadi va kernelga "X signali kelganda standart amal o'rniga mening shu funksiyamni ishga tushir" deb aytadi. To'g'ri yozilgan xizmatdagi muloyim to'xtash mantiqi aynan shu mexanizmga asoslanadi: jarayon amal o'rtasida shunchaki g'oyib bo'lmasligi uchun asosiy siklga joriy ish birligini tugatib, toza chiqishni buyuradigan bayroq o'rnatadigan SIGTERM ishlovchisi.

strace -e trace=rt_sigaction -p 22110

Ishlab turgan jarayonga qisqa vaqt strace ni ulab, boshqa terminaldan unga signal yuborish jarayon shu signal uchun haqiqatan o'z ishlovchisini ro'yxatdan o'tkazganmi yoki kernelning standart amaliga tayanayotganini real vaqtda ko'rsatishi mumkin. Bu xizmat nima uchun o'z hujjatlarida da’vo qilinganidek SIGHUP ga javob bermayotgandek ko'rinishini tashxislashda foydali.

Intervyuda

Keng tarqalgan intervyu savoli: "nega SIGKILL ni ushlab bo'lmaydi va bu amalda nima uchun muhim?" Kernel darajasidagi javob: SIGKILL va SIGSTOP oddiy signal yetkazish va munosabat mexanizmini butunlay chetlab o'tadi va shu bilan jarayonning signallarni qayta ishlashidagi xatolardan qat’i nazar, administratorda har qanday jarayonni tugatish yoki pauza qilishning har doim yo'li bo'lishini kafolatlaydi. Amaliy oqibati esa ba’zan o'ylanganining aksi: SIGKILL ni ushlab bo'lmasligi aynan uning birinchi tanlov emas, oxirgi chora bo'lishi kerakligining sababi — jarayon qulflarni bo'shatish, ma’lumotlarni diskka yozish yoki vaqtinchalik holatni tozalash imkoniyatini olmaydi. Yuqorida aytilgan buzilish va resurslar sizib chiqishi muammolarining bevosita sababi ham shu.

Zombilar: bola jarayonning chiqish holati hech qachon yig'ib olinmaganda

Jarayon tugaganda u jarayonlar jadvalidan darhol yo'qolmaydi — ota jarayon o'sha holatni yig'ib olish uchun wait() (yoki waitpid()) ni chaqirmaguncha u faqat o'z chiqish holatini saqlab turadigan zombiga (STAT — Z) aylanadi. Hech qachon wait() ni chaqirmaydigan ota jarayon — odatda bu xato, ba’zan esa bola jarayonlarni ishga tushirib, ularni hech qachon tekshirmaydigan haqiqatan oddiy skript — zombilar to'planib borishiga sabab bo'ladi.

ps -eo pid,ppid,stat,cmd | awk '$3 ~ /Z/'

Kichik va barqaror sondagi o'tkinchi zombilar odatiy holat — har bir bola jarayon chiqish va tozalanish o'rtasida qisqa vaqt shu holatdan o'tadi. Vaqt o'tishi bilan o'sib boradigan zombilar soni, ayniqsa ularning hammasi bitta ota PID ga ega bo'lsa, ota jarayonda haqiqiy tozalash (reaping) xatosi borligini ko'rsatadi.

Note

Zombi jarayonni o'ldirib bo'lmaydi — u allaqachon o'lgan; faqat uning jarayonlar jadvalidagi yozuvi tozalanishini kutib qolgan. Unga istalgan signal, jumladan SIGKILL yuborish ham hech qanday ta’sir qilmaydi. Yagona yechim — ota jarayonning wait() ni chaqirishi. Bu yo ota jarayon kodini tuzatishni, yo ota jarayonning o'zi javob bermayotgan bo'lsa, uni tugatishni anglatadi (bunda zombi PID 1 yoki subreaper’ga qayta biriktiriladi, ular esa uni to'g'ri tozalaydi).

Real vaziyat: xizmat odatdagi to'xtatishga javob bermayapti

Muammo. systemctl stop catalog.service qaytadi, lekin sozlangan kutish muddatidan keyin ham systemctl status jarayon ishlayotganini ko'rsatyapti va deploy pipeline’i endi uni kutib qotib qolgan.

Avval jarayonning haqiqiy holatini tekshiring:

systemctl status catalog.service
ps -o pid,ppid,stat,cmd -p "$(systemctl show -p MainPID --value catalog.service)"
    PID   PPID STAT CMD
  18422      1 D    /srv/catalog/current/bin/catalog

D STAT i (signalni shunchaki e’tiborsiz qoldirish emas, uzilmas uyqu) asosiy topilma: jarayon kernel ichida I/O amalida bloklangan va loyihaga ko'ra, aynan shu kernel amali tugamaguncha yoki uning muddati o'tmaguncha uni hech qanday signal, jumladan SIGTERM va hatto SIGKILL ham uza olmaydi.

U nimada bloklanganini tasdiqlang:

cat /proc/18422/wchan; echo
sudo cat /proc/18422/stack 2>/dev/null | head -5

Xulosa. Agar jarayon haqiqatan qotib qolgan disk yoki tarmoq fayl tizimi amalida D holatida tursa, ostidagi I/O hal bo'lmaguncha yoki kernel darajasida uning muddati o'tmaguncha hech qanday signal uni tugatmaydi. Bu ilova SIGTERM ni shunchaki e’tiborsiz qoldirishidan tubdan farq qiladigan holat va SIGKILL ni qayta-qayta yuborish yordam bermaydi. Haqiqiy yechim jarayonning o'zini emas, qotib qolgan I/O manbasini (javob bermayotgan NFS server, ishdan chiqayotgan disk) nishonga oladi; I/O tugagach yoki kernel undan voz kechgach, jarayonni odatdagidek o'ldirish mumkin bo'ladi. Agar buning o'rniga jarayon S yoki R STAT ini ko'rsatsa va SIGTERM dan keyin shunchaki hech qachon chiqmasa, bu ilovaning o'z signal ishlovchisi buzilgani yoki yo'qligiga ishora qiladi — to'g'ri qayta yuklash/to'xtatish signali uchun uning hujjatlarini tekshirishga arziydi — va faqat shundan keyingina SIGKILL ga o'tish o'rinli, garchi qo'pol bo'lsa ham, keyingi qadam bo'ladi.

Keng tarqalgan xatolar

Birinchi qadam sifatida kill -9 ga murojaat qilish

Bu jarayon muloyim SIGTERM da ishga tushirgan bo'ladigan har qanday tozalash kodini o'tkazib yuboradi va buzilgan ma’lumotlar fayllari, bo'shatilmagan qulflar va yetim qolgan vaqtinchalik holat xavfini tug'diradi. Har doim avval SIGTERM ni sinab ko'ring va oqilona vaqt kuting.

SIGHUP har doim "qayta yuklash" degani deb o'ylash

Ilovaga xos ishlovchi bo'lmasa, SIGHUP ning standart amali — tugatish. Muayyan daemon uni "konfiguratsiyani qayta yukla" deb qayta talqin qilishi butunlay o'sha daemon’ning o'z kodiga bog'liq — bu kelishuv hamma joyda qo'llanadi deb o'ylamasdan, uning hujjatlarini tekshiring.

Zombini o'ldirishga urinish

Zombi allaqachon o'lgan; hech qanday signal unga ta’sir qilmaydi. Yechim zombi yozuvining o'zini emas, wait() ni chaqirmagan ota jarayonni nishonga oladi.

Avval tekshirmasdan keng pkill andozasini ishlatish

pkill -f butun buyruq qatoriga nisbatan moslaydi va jimgina xuddi shu satrni o'z ichiga olgan, bog'liq bo'lmagan jarayonlarni ham ushlab olishi mumkin. Avval xuddi shu andoza bilan pgrep -af ni bajaring va mos kelgan har bir qatorni o'qing.

SIGKILL D holatidagi jarayonni darhol tugatadi deb kutish

Kernel I/O amalida uzilmas uyquda bloklangan jarayonni aynan shu amal hal bo'lmaguncha hech qanday signal, jumladan SIGKILL ham tugata olmaydi. O'ldirishga urinishni takrorlash o'rniga ostidagi qotib qolgan I/O ni tashxislang.

Mashqlar

  1. Fonda sleep 300 & ni ishga tushiring, unga SIGTERM yuboring va ps bilan u chiqqanini tasdiqlang. Buni SIGSTOP, so'ng ps -o stat, keyin SIGCONT bilan takrorlang va har bir qadamda jarayon bilan nima sodir bo'lganidagi farqni tasvirlab bering.
  2. Tegishli signal raqamlarini keltirib, nega kill -9 <pid> va kill -SIGSTOP <pid> ni nishondagi jarayon ushlab qola olmasligini, kill -15 <pid> va kill -SIGTSTP <pid> ni (Ctrl+Z dan) esa ushlab qola olishini tushuntiring.
  3. Tizimingizda SIGHUP orqali konfiguratsiyani qayta yuklashni qo'llab-quvvatlaydigan xizmatni toping (yoki shunday xizmat haqida fikr yuriting) va nginx uchun ko'rsatilgan andozaga amal qilib, unga signal yuborishdan oldin uning konfiguratsiyasini tekshirish uchun ishlatadigan aniq buyruqlar ketma-ketligini yozing.
  4. Jarayon Z STAT ini ko'rsatmoqda, bir soatdan ko'proq vaqtdan beri mavjud va bitta PPID ga ega qo'shni jarayonlar soni o'sib bormoqda. Javobgar ota jarayonni aniqlash uchun ishlatadigan diagnostika buyruqlari ketma-ketligini yozing va aslida nimani tuzatish kerakligini tushuntiring.

Mashqni bajardim deyish uchun: ishlab turgan jarayonga nisbatan birinchi amal sifatida SIGKILL ni taklif qiladigan har qanday javob noto'g'ri — agar aynan shu holat uchun SIGTERM samarasiz ekani allaqachon tasdiqlanganini yozma ravishda asoslab bera olmasangiz.

Manbalar

  • Linux man-pages: signal(7): https://man7.org/linux/man-pages/man7/signal.7.html
  • Linux man-pages: kill(1), kill(2): https://man7.org/linux/man-pages/man1/kill.1.html
  • Linux man-pages: pkill(1), killall(1): https://man7.org/linux/man-pages/man1/pkill.1.html
  • Linux man-pages: sigaction(2): https://man7.org/linux/man-pages/man2/sigaction.2.html
  • Linux man-pages: wait(2), waitpid(2): https://man7.org/linux/man-pages/man2/waitpid.2.html
  • Linux man-pages: proc(5) — /proc/[pid]/stat, /proc/[pid]/wchan: https://man7.org/linux/man-pages/man5/proc.5.html
  • freedesktop.org: systemd.service — ExecReload=, TimeoutStopSec=: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html