Linux I/O Scheduler Tuning: mq-deadline, none, BFQ
16 min citire - 1 iunie 2026

Cum să alegeți și să reglați planificatorul Linux I/O potrivit pentru volumele de lucru NVMe, SATA și HDD, cu comenzi sysfs, reguli udev și pași de benchmarking fio.
Reglarea programatorului I/O Linux: mq-deadline, none și BFQ
Programatorul I/O Linux decide ordinea în care cererile de citire și scriere ajung la dispozitivul dvs. de stocare, iar alegerea corectă depinde aproape în totalitate de hardware-ul dvs. Utilizați none pentru NVMe, mq-deadline pentru SSD-uri SATA și HDD-uri care rulează sarcini de lucru mixte și bfq atunci când trebuie să împiedicați un proces să le blocheze pe celelalte. Acest ghid prezintă modul în care funcționează cele trei programatoare principale, cum să le potriviți cu sarcina dvs. de lucru și cum să le reglați și să verificați rezultatul.
Dacă doriți un ghid practic înainte de a citi, acest videoclip prezintă noțiunile de bază privind comutarea și testarea programatoarelor din terminal.
Diferențele dintre mq-deadline, none și BFQ
Fiecare programator gestionează cererile cu o strategie diferită. Cunoașterea diferențelor dintre ele vă permite să alegeți în mod deliberat, în loc să rulați ceea ce a ales kernelul la pornire.
mq-deadline
Programatorul mq-deadline programator se asigură că nicio cerere nu așteaptă la nesfârșit. Acesta menține cozi separate și sortate pentru citiri și scrieri, ordonându-le după adresa blocului logic (LBA) pentru a reduce timpul de căutare, și impune termene limită: 500 ms pentru citiri și 5 secunde pentru scrieri în mod implicit. Când o cerere atinge termenul limită, aceasta sare în fața cozii.
Citirile au prioritate față de scrieri, deoarece citirile blochează de obicei aplicația, în timp ce scrierile sunt gestionate asincron. Pentru a împiedica blocarea completă a scrierilor, programatorul procesează un lot de scrieri restante după un număr stabilit de citiri. Rezultatul este o latență scăzută constantă, ceea ce îl face foarte potrivit pentru serverele de baze de date și orice sarcină de lucru care combină citirile și scrierile.
niciuna
Programatorul none programator nu face aproape nimic. Acesta transmite cererile direct către dispozitiv în ordinea „primul intrat, primul ieșit”, fără reordonare, îmbinare sau prioritizare. Acest lucru se potrivește unităților NVMe moderne, care își gestionează propriile cozi interne și pot urmări zeci de mii de cereri în curs de desfășurare simultan. Eliminarea stratului de programare software oferă cea mai scurtă cale posibilă de la aplicație la dispozitiv, ceea ce este exact ceea ce își doresc sarcinile de lucru NVMe cu debit ridicat.
Problema este că acest lucru funcționează doar atunci când hardware-ul poate programa inteligent pe cont propriu. Pe HDD-uri sau SSD-uri SATA cu cozi superficiale, omiterea reordonării software-ului de obicei înrăutățește performanța, nu o îmbunătățește.
BFQ
BFQ (Budget Fair Queuing) pune echitatea pe primul loc. În loc de intervale de timp, acesta alocă fiecărui proces un buget măsurat în sectoare de disc. Citirile secvențiale mari primesc bugete mai mari pentru a menține un debit ridicat, în timp ce sarcinile sensibile la latență primesc bugete mai mici, astfel încât să fie procesate rapid, iar o buclă de feedback ajustează bugetele pe măsură ce se execută.
BFQ menține sarcinile interactive receptive chiar și sub sarcină grea, astfel încât redarea video sau o interogare a bazei de date rămâne fluidă în timp ce un transfer de fișiere mari rulează în fundal. Această echitate costă CPU. Supraîncărcarea sa per cerere este de aproximativ 1,9 microsecunde, de aproximativ trei ori mai mare decât cea a mq-deadline, iar pe un nucleu ARM mai lent, acea supraîncărcare limitează debitul cu mult sub ceea ce același programator atinge pe un cip x86 rapid. Pe serverele unde debitul brut și eficiența CPU contează cel mai mult, acest compromis este greu de justificat.
| Programator | Algoritm | Sarcină suplimentară pentru CPU | Cel mai bun hardware | Obiectiv principal |
|---|---|---|---|---|
mq-deadline | LBA sortat cu termene limită | Redus (~0,7 µs/solicitare) | SSD-uri SATA, HDD-uri, discuri virtuale | Latență scăzută previzibilă |
none | FIFO, fără reordonare | Neglijabil | SSD-uri NVMe | Debit maxim |
bfq | Bugete de partajare proporțională | Moderat (~1,9 µs/solicitare) | HDD-uri, sisteme partajate și desktop | Echitate și capacitate de răspuns |
Alegerea unui programator potrivit pentru volumul dvs. de lucru
Două lucruri determină alegerea programatorului potrivit: hardware-ul de stocare și modelul de acces al aplicației. Începeți cu hardware-ul. Dacă dispozitivul reordonează deja cererile, cum ar fi o unitate NVMe cu firmware compatibil, programarea software nu face decât să adauge o sarcină suplimentară, așa că none câștigă. Pe HDD-urile rotative, unde timpul de căutare domină, reordonarea software reduce latența, așa că mq-deadline sau bfq sunt alegerile mai bune. SSD-urile SATA se situează între cele două: mai rapide decât HDD-urile, dar fără cozile adânci ale NVMe, ceea ce face ca mq-deadline se potrivește.
Aceeași logică se aplică atunci când altceva se ocupă deja de programare pentru dvs. Mașinile virtuale oaspete de pe virtio-blk se bazează pe gazdă pentru a programa I/O, iar controlerele RAID hardware cu cache de scriere ulterioară își optimizează propria ordonare. În ambele cazuri none evită să plătească de două ori pentru aceeași muncă.
Modelul de acces este al doilea factor. O bază de date care efectuează mii de citiri aleatorii de 4K pe secundă nu are nimic în comun cu o sarcină de antrenare care transmite în flux blocuri secvențiale mari dintr-o matrice NVMe, iar acestea necesită programatoare diferite. Tabelul de mai jos corelează sarcinile de lucru obișnuite cu un punct de plecare.
| Sarcina de lucru | Stocare | Programator | Motiv |
|---|---|---|---|
| Antrenare AI/ML | SSD NVMe | none | Debit secvențial ridicat; firmware-ul gestionează cozile |
| Baza de date OLTP | SSD NVMe | none | I/O aleatoriu cu latență redusă; evită suprasolicitarea software-ului |
| Baza de date OLTP | SSD SATA | mq-deadline | Previne blocarea scrierii; latență previzibilă la coadă |
| Depozit de date / OLAP | NVMe / SSD rapid | none | Cozi paralele profunde; lățime de bandă maximă |
| Gazduire web generală | SSD SATA / HDD | mq-deadline | Răspuns constant pentru operațiuni I/O mixte cu fișiere mici |
| Gazduire partajată / multi-tenant | HDD / SSD | bfq | Echitate între chiriași; oprește monopolizarea I/O |
| Mașină virtuală oaspete | virtio-blk | none | Gazda deja programează; programarea dublă risipește CPU |
| Backup / arhivare | HDD | mq-deadline | Debit secvențial cu prevenirea epuizării |
Există o singură excepție care merită menționată. Chiar și pe NVMe, dacă latența de coadă la p99 sau p999 este indicatorul care vă interesează, cum ar fi în sistemele financiare, mq-deadline poate depăși none prin impunerea unor termene stricte și prevenirea cererilor întârziate ocazionale.
Modificarea și reglarea parametrilor programatorului
Atât comutarea programatorilor, cât și reglarea parametrilor acestora se realizează prin sysfs, fără a fi necesară repornirea sistemului pentru a testa o modificare.
Comutarea programatorului activ
Verificați ce este disponibil pentru un dispozitiv, unde valoarea dintre paranteze este cea activă:
cat /sys/block/sda/queue/schedulerComutați la un alt programator în timpul rulării. Aceasta are efect imediat, dar nu se păstrează după o repornire:
echo bfq | sudo tee /sys/block/sda/queue/schedulerDacă bfq nu este listat, încărcați mai întâi modulul:
sudo modprobe bfqPentru a face o alegere persistentă, utilizați o regulă udev în locul vechiului elevator= parametru al kernel-ului, care nu mai schimbă programatorul pe RHEL 9 și versiuni similare. Această regulă setează mq-deadline pentru toate discurile SCSI nerotaționale din /etc/udev/rules.d/60-io-scheduler.rules:
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"Reîncărcați-o și aplicați-o fără a reporni:
sudo udevadm control --reload-rules && sudo udevadm triggerPe sistemele bazate pe RHEL, profilurile TuneD îndeplinesc aceeași sarcină prin profiluri la nivel de sistem, în loc de reguli per dispozitiv.
Parametri care merită reglați
Fiecare programator își expune parametrii de reglare sub /sys/block/<device>/queue/iosched/. Pentru mq-deadline, termenele limită sunt principalele pârghii. Bazele de date sensibile la latență de pe SSD-urile SATA beneficiază de cele mai scurte:
echo 100 | sudo tee /sys/block/sda/queue/iosched/read_expire
echo 1000 | sudo tee /sys/block/sda/queue/iosched/write_expirePentru bfq pe sistemele cu debit ridicat, dezactivarea euristicilor de latență crește debitul:
echo 0 | sudo tee /sys/block/sda/queue/iosched/low_latency
echo 0 | sudo tee /sys/block/sda/queue/iosched/slice_idle| Programator | Parametru | Implicit | Obiectiv de reglare |
|---|---|---|---|
mq-deadline | read_expire | 500 ms | Mai mic pentru un răspuns de citire mai rapid |
mq-deadline | write_expire | 5000 ms | Mai mic pentru a reduce latența de scriere |
mq-deadline | writes_starved | 3 | Creșteți pentru sarcini cu citire intensă |
mq-deadline | fifo_batch | 16 | Setați la 1 pentru o latență minimă |
bfq | low_latency | 1 | Setați la 0 pentru un debit maxim |
bfq | slice_idle | 8 ms | Setați la 0 pentru SSD-uri sau RAID |
bfq | strict_guarantees | 0 | Setați la 1 pentru partajarea strictă a lățimii de bandă |
Pentru găzduirea partajată, BFQ se potrivește bine cu cgroups v2. Atribuirea io.weight vă permite să alocați unui proces de bază de date de zece ori mai multă lățime de bandă decât unei sarcini de backup, de exemplu, astfel încât activitatea de fundal să nu afecteze traficul interactiv. Indiferent de modificările pe care le faceți, costul mai ridicat pe cerere al BFQ se acumulează pe sistemele limitate de CPU și cu IOPS ridicat, așa că efectuați un test de performanță înainte de a implementa modificările.
Verificarea performanței după optimizare
Înregistrați întotdeauna o valoare de referință înainte de a modifica ceva. Fără aceasta, nu aveți cum să știți dacă o modificare a fost utilă.
fio este instrumentul standard pentru acest lucru. Acesta reproduce modele specifice de încărcare prin dimensiunea blocului, adâncimea cozii și setările motorului I/O. Treceți întotdeauna --direct=1 astfel încât să ocolească cache-ul de pagini și să măsoare direct programatorul și dispozitivul, în loc de citirile din cache. Potriviți testul cu sarcina de lucru reală:
| Sarcina de lucru | Parametrii fio |
|---|---|
| Baza de date OLTP | --rw=randread --bs=4k --iodepth=32 --direct=1 |
| Depozit de date | --rw=read --bs=1m --iodepth=32 --direct=1 |
| Jurnal de scriere anticipată / redo | --rw=write --bs=4k --iodepth=1 --direct=1 |
| Stocare de obiecte | --rw=randrw --bs=64k --iodepth=64 --direct=1 |
Rulați același test cu iodepth valori de la 1 la 256 pentru a găsi punctul de saturație al dispozitivului, adâncimea la care IOPS încetează să crească și latența crește brusc. Pentru monitorizarea în timp real după o modificare, iostat -x 1 raportează metricile care contează: r_await și w_await pentru latența de finalizare a citirii și scrierii, aqu-sz pentru adâncimea medie a cozii și %util pentru utilizarea dispozitivului. Când %util se situează aproape de 100%, hardware-ul este limita și nicio modificare a programatorului nu va ajuta.
Pentru a separa costul software-ului de cel al hardware-ului, rulați blktrace cu btt. Acesta împarte latența în Q2D, timpul petrecut în coada software-ului, și D2C, timpul necesar dispozitivului pentru a procesa solicitarea. Dacă Q2D domină, programatorul este gâtul de sticlă. Dacă D2C domină, hardware-ul este.
Un lucru de reținut atunci când citiți rezultatele: alegerea programatorului modelează în principal coada distribuției latenței, nu mediana. Trecerea de la none la mq-deadline pe NVMe ar putea crește latența mediană cu câteva microsecunde, reducând în același timp latența p99 și p999 la jumătate. Pentru serviciile destinate utilizatorilor, limitate de SLA-uri, acest compromis merită aproape întotdeauna, motiv pentru care măsurarea latenței cozii, și nu a debitului mediu, este scopul exercițiului.
Alegerea programatorului potrivit
Reglarea programatorului înseamnă adaptarea algoritmului la hardware și la modelul de acces, apoi verificarea acestuia prin măsurători. Versiunea scurtă:
- NVMe: utilizați
noneși lăsați firmware-ul să se ocupe de coada de așteptare. - SSD-uri SATA și HDD-uri cu I/O mixt: utilizați
mq-deadlinepentru o latență previzibilă. - Gazde partajate sau multi-tenant: utilizați
bfqpentru a împiedica o sarcină de lucru să le blocheze pe celelalte. - Urmăriți latența, nu mediana: modificările programatorului apar la p99 și p999, așa că asta trebuie măsurat.
- Asigurați-vă că este persistent: utilizați reguli udev sau TuneD, niciodată parametrul
elevator=.
Pentru a profita la maximum de orice programator, este nevoie de hardware care să țină pasul. Dacă aveți nevoie de servere bazate pe NVMe, construite pentru sarcini de lucru cu debit ridicat și latență redusă, explorați opțiunile VPS ale FDC.
De ce este important să aveți un VPS puternic și nemeditat
Un VPS neevaluat oferă o lățime de bandă forfetară la o viteză fixă a portului. Cum diferă de planurile cu contorizare, când merită și ce trebuie să verificați înainte de cumpărare.
7 min citire - 9 mai 2025
Managementul memoriei în Linux: Swap, OOM Killer și Cgroups
12 min citire - 31 mai 2026

Aveți întrebări sau aveți nevoie de o soluție personalizată?
Opțiuni flexibile
Acoperire globală
Implementare instantanee
Opțiuni flexibile
Acoperire globală
Implementare instantanee