Tarkibga o'tish

Jarayon ustuvorligi: nice, renice va CPU vaqtini adolatli taqsimlash

Odatiy serverda istalgan lahzada ishga tayyor jarayonlar CPU yadrolaridan ancha ko'p bo'ladi: veb-server, ma’lumotlar bazasi, zaxira nusxa skripti va monitoring agenti bir vaqtda CPU vaqtini xohlaydi, lekin har bir yadro bir vaqtda aynan bitta ko'rsatmalar oqimini bajara oladi. Kernelning rejalashtiruvchisi (scheduler) soniyasiga ko'p marta qaysi ishga tayyor jarayon yadroni keyingi bo'lib va qancha muddatga olishini hal qiladi. Ko'pincha standart rejalashtirish siyosati yetarli va ko'rinmaydi. U muhim bo'ladigan paytlar aynan shu yerda ko'rib chiqiladi: fondagi paketli ish interaktiv xizmatni CPU’siz qoldirmasligi kerak bo'lganda yoki muhim jarayonni kamroq muhim ish ortida kutib qolishdan himoya qilish kerak bo'lganda.

Bu maqolada nice qiymatlari rejalashtiruvchining qarorlariga qanday ta’sir qilishini, ularni nice va renice bilan qanday o'rnatish va o'zgartirishni ko'rib chiqamiz. Shuningdek, faqat nice har qanday ustuvorlik muammosini hal qilmagani uchun real vaqt (real-time) rejalashtirish siyosatlari va I/O ustuvorligi (ionice) shu manzaraga qanday sig'ishini ham ko'ramiz.

Nice qiymatlari: kafolat emas, og'dirish

Linux’ning oddiy jarayonlar uchun standart rejalashtiruvchisi (hozir ishlatilayotgan ko'pchilik kernellarda Completely Fair Scheduler, CFS) har bir jarayonga bir xil, belgilangan vaqt bo'lagini bermaydi. Buning o'rniga har bir jarayonning -20 (eng yuqori rejalashtirish ustuvorligi) dan 19 (eng past) gacha bo'lgan nice qiymati bor va rejalashtiruvchi undan bitta yadro uchun raqobatlashayotgan boshqa jarayonlarga nisbatan jarayon qancha CPU vaqti olishga haqli ekanini hisoblashda vazn sifatida foydalanadi. Standart, o'zgartirilmagan jarayon 0 nice qiymati bilan ishlaydi.

Nom ataylab ma’noli tanlangan: jarayonning nice qiymatini oshirish uni boshqalarga nisbatan "muloyimroq" (nicer) qiladi — u boshqa jarayonlar ko'proq ishlashi uchun ixtiyoriy ravishda kichikroq CPU ulushiga rozi bo'ladi.

ps -eo pid,ni,pri,comm --sort=ni | head
    PID  NI PRI COMMAND
  22110 -10  30 postgres
   1842   0  20 nginx
  30044  10  10 backup.sh

NI — siz o'rnatgan nice qiymati; PRI esa nice qiymati ta’sir qiladigan, kernel hisoblagan haqiqiy rejalashtirish ustuvorligi (bu yerda yuqoriroq PRI ertaroq rejalashtirilishini bildiradi). PRI ning aniq raqamli qoidasi NI nikidan farq qiladi va bu ko'p chalkashlikka sabab bo'ladi; biror narsani sozlayotganda har doim PRI emas, NI bo'yicha fikr yuriting.

Warning

Nice qiymati — kafolatlangan ulush ham, qat’iy chegara ham emas, balki nisbiy og'dirish. Agar ustuvorligi pasaytirilgan jarayon (NI 19) aks holda bo'sh turgan yadrodagi yagona ishga tayyor jarayon bo'lsa, u baribir o'sha yadroning 100% ini oladi. Nice qiymatlari faqat bir nechta jarayon aynan bir vaqtda bitta CPU uchun haqiqatan raqobatlashganda ahamiyatli. Yuqori nice qiymatini o'rnatish bo'sh tizimda jarayonning CPU sarfini cheklamaydi.

Jarayonni tanlangan ustuvorlik bilan ishga tushirish: nice

nice -n 15 backup-script.sh

-n 15 backup-script.sh ni 15 nice qiymati bilan ishga tushiradi — bu bitta yadro uchun raqobatlashayotgan har qanday muhimroq narsaga CPU vaqtini osonlikcha bo'shatib beradigan past ustuvorlikli fon ishi. Aniq daraja ko'rsatilmasa, nice shell’ning joriy nice qiymatiga standart siljishni (odatda 10) qo'llaydi.

Ustuvorlikni standartdan (0) yuqori ko'tarish yuqori huquq talab qiladi, chunki imtiyozsiz jarayonga boshqa hamma narsadan ustuvorlikni erkin egallashga ruxsat berish tizimning qolgan qismini CPU’siz qoldirishning oson yo'li bo'lardi:

sudo nice -n -5 critical-batch.sh

sudo siz manfiy nice qiymatini o'rnatishga uringan oddiy foydalanuvchi shell va tizim sozlamalariga qarab xato yoki jimgina cheklangan qiymat oladi. So'ralgan qiymat kuchga kirgan deb o'ylamasdan, keyin har doim ps -o ni bilan tekshiring.

Ishlab turgan jarayonning ustuvorligini o'zgartirish: renice

nice faqat jarayon ishga tushayotgan paytda qo'llanadi. Allaqachon ishlab turgan jarayonni sozlash uchun renice dan foydalaning:

renice -n 10 -p 22110
22110 (process ID) old priority 0, new priority 10

-p to'g'ridan-to'g'ri PID ni nishonga oladi. renice muayyan foydalanuvchiga tegishli barcha jarayonlarni qayta nishonga olish uchun -u <user> ni va jarayonlar guruhi uchun -g <group> ni ham qabul qiladi. Bu har bir PID ni alohida qidirish o'rniga butun paketli ishning bola jarayonlari ustuvorligini bitta buyruq bilan pasaytirish uchun foydali.

renice -n 15 -u batch-runner

nice dagidek, nice qiymatini joriy darajasidan pastga yoki umuman 0 dan pastga tushirish (jarayonni ko'proq afzal qilish) buni qilish huquqini talab qiladi. Imtiyozsiz foydalanuvchi o'z jarayonining nice qiymatini faqat oshira oladi (uni kamroq afzal qila oladi), hech qachon pasaytira olmaydi. Bu foydalanuvchiga administrator ataylab cheklagan jarayonning ustuvorligini qaytarib olishga yo'l qo'ymaydi.

Real vaqt rejalashtirish: nice yetarli bo'lmaganda

Nice qiymatlari ustuvorlikni faqat oddiy, "imkon qadar" (best-effort) rejalashtirish sinfi ichida sozlaydi. Haqiqatan boshqa hamma narsani siqib chiqarishi shart bo'lgan jarayon uchun — past kechikishli audio pipeline, ba’zi sanoat boshqaruv dasturlari — Linux real vaqt rejalashtirish siyosatlarini (SCHED_FIFO, SCHED_RR) taklif qiladi. Ular nice qiymati boshqaradigan barcha oddiy jarayonlardan yuqori turadigan butunlay alohida, yuqoriroq ustuvorlikli sinfda joylashgan:

chrt -f -p 50 22110
chrt -p 22110
pid 22110's current scheduling policy: SCHED_FIFO
pid 22110's current scheduling priority: 50

chrt -f real vaqt ustuvorligi 50 bilan SCHED_FIFO ni o'rnatadi (bir xil real vaqt ustuvorligidagi jarayonlar orasida birinchi kelgan birinchi xizmat qilinadi va u bloklanmaguncha yoki joy bo'shatmaguncha ishlaydi). Real vaqt ustuvorliklari 1–99 oralig'ida bo'ladi, 99 eng yuqorisi — bu oddiy nice qiymatlaridan alohida, belgilangan raqamli oraliq.

Danger

Real vaqt rejalashtirish nice dan tubdan farq qiladigan vosita va noto'g'ri ishlatilsa, uning ta’sir doirasi ancha katta. Hech qachon ixtiyoriy bloklanmaydigan yoki joy bo'shatmaydigan SCHED_FIFO jarayoni tizimdagi har bir oddiy jarayonni, jumladan oddiy ustuvorlikda ishlaydigan muhim kernel xizmat thread’larini ham CPU’siz qoldirishi va mashinani faqat apparatni qayta yoqish bilan tiklanadigan darajada javob bermaydigan holatga keltirishi mumkin. Umumiy maqsadli xizmatga avval bir martalik mashinada sinab ko'rmasdan real vaqt siyosatini o'rnatmang va muayyan ish yuki cheksiz qattiq siklda aylanmasdan, vaqti-vaqti bilan sched_yield() ni chaqirishi yoki bloklanishini doim tasdiqlang.

CPU ustuvorligi I/O ustuvorligi emas: ionice

Qulay nice qiymatiga ega jarayon ham sekin disk I/O ni kutayotgan bo'lsa, baribir jiddiy kechikishi mumkin, chunki nice qiymatlari kernel blok I/O so'rovlariga qaysi tartibda xizmat ko'rsatishini emas, faqat CPU rejalashtirishini boshqaradi. ionice ostidagi I/O rejalashtiruvchisi uni qo'llab-quvvatlasa, aynan shu alohida o'qni hal qiladi (odatda cfq yoki bfq bilan; NVMe qurilmalarida keng tarqalgan standart none/mq-deadline ostida kamroq samarali):

ionice -c 3 -p 22110
ionice -p 22110
idle

-c 3 idle I/O sinfini o'rnatadi — bu jarayonning I/O so'rovlariga faqat boshqa hech bir jarayonga disk umuman kerak bo'lmaganda xizmat ko'rsatiladi. Bu oldingi plandagi diskka bog'liq ishga hech qanday ta’sir qilmasligi kerak bo'lgan fondagi zaxira nusxa yoki indekslash ishi uchun ideal. -c 2 (best-effort, standart) undan keyin 0–7 ustuvorlik darajasini qabul qiladi; -c 1 (real vaqt) imtiyozli, kechikishga o'ta sezgir I/O uchun ajratilgan va keng qo'llansa, real vaqt CPU rejalashtirishidagi kabi resurssiz qoldirish xavfiga ega.

ionice -c 3 nice -n 19 tar -czf /backup/full-backup.tar.gz /srv/data

Ikkalasini bitta qatorda birlashtirish — eng past CPU ustuvorligi va idle I/O sinfi — mashinada ishlayotgan boshqa hamma narsa uchun amalda ko'rinmas bo'lishi kerak bo'lgan zaxira nusxa ishi uchun standart andoza.

Real vaziyat: tungi zaxira nusxa veb-serverni sekinlashtirmoqda

Muammo. Har kecha soat 02:00 da tar asosidagi zaxira nusxa ishi ishga tushadi va monitoring shu oraliqda veb-serverdagi so'rovlar kechikishi keskin oshayotganini ko'rsatadi. Zaxira nusxaning o'zini kechiktirmasdan yoki buzmasdan uning ta’sirini kamaytirish kerak.

Biror narsani o'zgartirishdan oldin sabab haqiqatan zaxira nusxa ekanini tasdiqlang:

ps -eo pid,ni,pcpu,pmem,etime,cmd | grep -E 'tar|backup'
top

Zaxira nusxa oralig'ida top ning %Cpu(s) qatorini tekshiring (Jarayonlarni kuzatish maqolasida ko'rilganidek). Agar zaxira nusxa faolligi bilan birga wa (I/O kutish) ham oshgan bo'lsa, to'siq disk raqobati va uni faqat nice hal qilmaydi; bu yerda kerakli vosita — ionice.

Zaxira nusxa jarayonlar guruhiga CPU va I/O ustuvorligini pasaytirishni birga qo'llang:

backup_pid=$(pgrep -f 'full-backup.sh' | head -1)
renice -n 19 -p "$backup_pid"
ionice -c 3 -p "$backup_pid"

Tekshiring:

ps -o pid,ni,cmd -p "$backup_pid"
ionice -p "$backup_pid"
    PID  NI CMD
  30044  19 /usr/local/bin/full-backup.sh
idle

Uzoq muddatli yaxshiroq yechim. Har kecha jarayon ishga tushgandan keyin uning ustuvorligini qo'lda o'zgartirish o'rniga, zaxira nusxaning o'z ishga tushirish buyrug'ini — uning cron yozuvi yoki systemd unit’ini — boshidanoq to'g'ri ustuvorlik bilan ishga tushadigan qilib tahrirlang:

ionice -c 3 nice -n 19 /usr/local/bin/full-backup.sh

Xulosa. Agar bu o'zgarishdan keyin zaxira nusxa oralig'idagi veb-server kechikishi yaxshilansa, asl muammo zaxira nusxa veb-server bilan teng sharoitda raqobatlashganidan kelib chiqqan CPU va/yoki I/O raqobati bo'lgan. Uning ustuvorligini manbaning o'zida (keyinchalik qo'lda bajariladigan renice da emas, ishga tushirish buyrug'ida) pasaytirish kelgusi har bir ishga tushirishda xuddi shu shikoyat takrorlanishining oldini oladi. Agar kechikish yaxshilanmasa, to'siq boshqa joyda — tarmoqda, ma’lumotlar bazasi so'rovi vaqtida yoki ilova darajasidagi raqobatda — va ustuvorlikni sozlash aynan shu alomat uchun noto'g'ri vosita bo'lgan.

Keng tarqalgan xatolar

nice bo'sh tizimda CPU sarfini cheklaydi deb kutish

Ustuvorligi pasaytirilgan jarayon, agar o'sha paytda unga hech kim raqib bo'lmasa, baribir yadroning 100% ini oladi. Nice qiymatlari faqat raqobat paytida ahamiyatli; ular CPU kvota mexanizmi emas (haqiqiy kvota vositasi — production mavzularida boshqa joyda ko'rib chiqiladigan cgroups CPU chegaralari).

NI va PRI ni adashtirish

PRI ning raqamli qoidasi (va uning aniq oralig'i) NI ning -20 dan 19 gacha shkalasi bilan bir xil emas. Ustuvorlikni har doim NI orqali o'rnating va u haqida NI bo'yicha fikr yuriting, PRI ga esa faqat kernel ichida hisoblanadigan, hosilaviy ko'rsatkich sifatida qarang.

Real vaqt rejalashtirishni kuchliroq nice sifatida ishlatish

SCHED_FIFO/SCHED_RR "o'ta manfiy nice qiymatlari" emas — ular butun oddiy rejalashtirish sinfini, jumladan -20 nice qiymatiga ega jarayon ham vaqtni bo'lishishi kerak bo'lgan jarayonlarni siqib chiqaradi. Real vaqt rejalashtirishga faqat haqiqatan qat’iy kechikish kafolatlarini talab qiladigan ish yuklari uchun va faqat bir martalik tizimda sinab ko'rgandan keyin murojaat qiling.

CPU ustuvorligini pasaytirib, I/O ni unutish

Qulay nice qiymati berilgan paketli ish faqat disk raqobati orqali ham interaktiv ishni to'xtatib qo'yishi mumkin. Sezilarli fayl I/O bajaradigan har qanday fon ishi uchun renice ni ionice bilan birga qo'llang.

Ishning faqat ota jarayoni ustuvorligini o'zgartirish

Shell skriptining o'z ustuvorligini o'zgartirish u keyinchalik ishga tushiradigan har bir bola jarayonga avtomatik o'tmaydi — agar skriptning o'zi kerakli nice qiymati bilan ishga tushirilmagan bo'lsa yoki butun jarayonlar guruhiga renice -p/-g qo'llanmagan bo'lsa. Har bir tegishli bola jarayon haqiqatan ko'zlangan ustuvorlikni meros qilib olganini ps --forest bilan tekshiring.

Mashqlar

  1. Ikkita CPU’ni band qiladigan siklni (yes > /dev/null & ni ikki marta) mos ravishda 0 va 19 nice qiymatlari bilan ishga tushiring, so'ng top dagi ikkalasining %CPU ustunini kuzating. Kuzatgan nisbatingizni belgilangan foiz taqsimoti bilan emas, rejalashtirish vazni orqali tushuntiring.
  2. O'zingizning joriy shell sessiyangizga nisbatan renice -n 10 -u <your-username> ni qo'llang va ps -o ni yordamida nima o'zgargani va nima o'zgarmaganini, shuningdek keyin uni yana 0 dan pastga tushirish nega sudo siz muvaffaqiyatsiz bo'lishini tushuntiring.
  3. Taxminiy nightly-export.sh skriptini keyinchalik sozlash o'rniga ishga tushgan paytidanoq eng past CPU ustuvorligi va idle I/O sinfi bilan ishga tushiradigan bitta buyruqni yozing.
  4. Hech narsani ishga tushirmasdan, ichida hech qanday bloklovchi chaqiruv bo'lmagan cheksiz siklli yomon yozilgan xizmatga chrt -f -p 99 ni o'rnatish nega xuddi shu xizmatga renice -n -20 ni o'rnatishdan xavfliroq ekanini tushuntiring.

Mashqni bajardim deyish uchun: "jarayonni nice qilish uning CPU sarfini cheklaydi" degan har qanday da’vo noto'g'ri va javoblaringizda bo'lmasligi kerak — to'g'ri ifoda har doim mutlaq chegara emas, raqobat ostidagi nisbiy ustuvorlik.

Manbalar

  • Linux man-pages: nice(1), renice(1): https://man7.org/linux/man-pages/man1/nice.1.html
  • Linux man-pages: sched(7): https://man7.org/linux/man-pages/man7/sched.7.html
  • Linux man-pages: chrt(1): https://man7.org/linux/man-pages/man1/chrt.1.html
  • Linux man-pages: ionice(1): https://man7.org/linux/man-pages/man1/ionice.1.html
  • Linux kernel hujjatlari: CFS scheduler design: https://www.kernel.org/doc/html/latest/scheduler/sched-design-CFS.html
  • Linux kernel hujjatlari: real-time scheduling: https://www.kernel.org/doc/html/latest/scheduler/sched-rt-group.html
  • Linux man-pages: setpriority(2), getpriority(2): https://man7.org/linux/man-pages/man2/setpriority.2.html