Messa a punto dello scheduler I/O di Linux: mq-deadline, none, BFQ
16 min di lettura - 1 giugno 2026

Come scegliere e mettere a punto il giusto I/O scheduler di Linux per i carichi di lavoro NVMe, SATA e HDD, con comandi sysfs, regole udev e passi di benchmarking fio.
Ottimizzazione dello scheduler I/O di Linux: mq-deadline, none e BFQ
Lo scheduler I/O di Linux decide l'ordine in cui le richieste di lettura e scrittura raggiungono il dispositivo di archiviazione, e la scelta giusta dipende quasi interamente dall'hardware. Utilizzare none per NVMe, mq-deadline per SSD SATA e HDD con carichi di lavoro misti, e bfq quando è necessario impedire che un processo ne blocchi altri. Questa guida illustra il funzionamento dei tre principali scheduler, come abbinarne uno al proprio carico di lavoro e come ottimizzarlo e verificarne il risultato.
Se desideri una guida pratica prima di leggere, questo video illustra le nozioni di base su come cambiare e testare gli scheduler dal terminale.
In che modo mq-deadline, none e BFQ differiscono
Ogni scheduler gestisce le richieste con una strategia diversa. Conoscere le loro differenze ti permette di scegliere consapevolmente invece di utilizzare ciò che il kernel ha selezionato all'avvio.
mq-deadline
Lo mq-deadline scheduler assicura che nessuna richiesta rimanga in attesa a tempo indeterminato. Mantiene code separate e ordinate per le letture e le scritture, ordinandole in base all'indirizzo di blocco logico (LBA) per ridurre il tempo di ricerca, e impone delle scadenze: 500 ms per le letture e 5 secondi per le scritture per impostazione predefinita. Quando una richiesta raggiunge la sua scadenza, salta in cima alla coda.
Le letture hanno la priorità sulle scritture, poiché le letture di solito bloccano l'applicazione mentre le scritture vengono gestite in modo asincrono. Per evitare che le scritture vengano completamente ignorate, lo scheduler gestisce un batch di scritture scadute dopo un numero prestabilito di letture. Il risultato è una bassa latenza costante, il che lo rende particolarmente adatto ai server di database e a qualsiasi carico di lavoro che mescoli letture e scritture.
nessuno
Lo none scheduler non fa praticamente nulla. Passa le richieste direttamente al dispositivo in ordine First-In-First-Out, senza riordino, unione o prioritizzazione. Ciò si adatta alle moderne unità NVMe, che gestiscono le proprie code interne e possono tracciare decine di migliaia di richieste in corso contemporaneamente. La rimozione del livello di scheduling software offre il percorso più breve possibile dall'applicazione al dispositivo, che è esattamente ciò che richiedono i carichi di lavoro NVMe ad alta velocità.
Il problema è che questo funziona solo quando l'hardware è in grado di eseguire la pianificazione in modo intelligente da solo. Su HDD o SSD SATA con code poco profonde, saltare il riordino software di solito peggiora le prestazioni, anziché migliorarle.
BFQ
BFQ (Budget Fair Queuing) mette al primo posto l'equità. Invece di intervalli di tempo, assegna a ciascun processo un budget misurato in settori del disco. Le letture sequenziali di grandi dimensioni ottengono budget più ampi per mantenere alto il throughput, mentre le attività sensibili alla latenza ottengono budget più ridotti in modo da essere servite rapidamente, e un ciclo di feedback regola i budget durante l'esecuzione.
BFQ mantiene reattive le attività interattive anche sotto carico pesante, quindi la riproduzione video o una query sul database rimane fluida mentre in background è in corso il trasferimento di un file di grandi dimensioni. Tale equità ha un costo in termini di CPU. Il suo overhead per richiesta è di circa 1,9 microsecondi, circa tre volte quello di mq-deadline, e su un core ARM più lento tale overhead limita il throughput ben al di sotto di quanto lo stesso scheduler raggiunga su un chip x86 veloce. Su server in cui la velocità effettiva e l'efficienza della CPU sono fondamentali, questo compromesso è difficile da giustificare.
| Scheduler | Algoritmo | Overhead della CPU | Hardware ottimale | Obiettivo principale |
|---|---|---|---|---|
mq-deadline | LBA ordinati con scadenze | Basso (~0,7 µs/richiesta) | SSD SATA, HDD, dischi virtuali | Bassa latenza prevedibile |
none | FIFO, nessun riordino | Trascurabile | SSD NVMe | Throughput massimo |
bfq | Budget a quota proporzionale | Moderato (~1,9 µs/richiesta) | HDD, sistemi condivisi e desktop | Equità e reattività |
Scegliere lo scheduler adatto al proprio carico di lavoro
Due fattori determinano lo scheduler giusto: l'hardware di archiviazione e il modello di accesso dell'applicazione. Iniziamo dall'hardware. Se il dispositivo riordina già le richieste, come un'unità NVMe con firmware compatibile, la pianificazione software aggiunge solo un sovraccarico, quindi none vince. Sugli HDD rotanti, dove il tempo di ricerca è dominante, il riordino software riduce la latenza, quindi mq-deadline o bfq sono le scelte migliori. Gli SSD SATA si collocano nel mezzo: più veloci degli HDD ma senza le code profonde dell’NVMe, ed è qui che mq-deadline si inserisce.
La stessa logica si applica quando qualcos'altro sta già gestendo la schedulazione per voi. Le VM guest su virtio-blk si affidano all'host per la schedulazione dell'I/O, mentre i controller RAID hardware con cache write-back ottimizzano autonomamente il proprio ordinamento. In entrambi i casi none si evita di pagare due volte per lo stesso lavoro.
Il modello di accesso è il secondo fattore. Un database che esegue migliaia di letture casuali da 4K al secondo non ha nulla in comune con un processo di addestramento che trasmette in streaming grandi blocchi sequenziali da un array NVMe, e richiedono scheduler diversi. La tabella sottostante mappa i carichi di lavoro comuni a un punto di partenza.
| Carico di lavoro | Archiviazione | Scheduler | Motivo |
|---|---|---|---|
| Addestramento AI/ML | SSD NVMe | none | Elevata velocità sequenziale; il firmware gestisce l'accodamento |
| Database OLTP | SSD NVMe | none | I/O casuale a bassa latenza; evita il sovraccarico del software |
| Database OLTP | SSD SATA | mq-deadline | Previene lo "write starvation"; latenza di coda prevedibile |
| Data warehouse / OLAP | NVMe / SSD veloce | none | Code parallele profonde; throughput massimo |
| Web hosting generico | SSD SATA / HDD | mq-deadline | Risposta costante per I/O misto su file di piccole dimensioni |
| Hosting condiviso / multi-tenant | HDD / SSD | bfq | Equità tra gli utenti; impedisce il monopolio dell'I/O |
| Macchina virtuale guest | virtio-blk | none | L'host esegue già la pianificazione; la doppia pianificazione comporta uno spreco di CPU |
| Backup / archiviazione | HDD | mq-deadline | Throughput sequenziale con prevenzione dello starvation |
C'è un'eccezione che vale la pena segnalare. Anche su NVMe, se la latenza di coda a p99 o p999 è la metrica che ti interessa, come nei sistemi finanziari, mq-deadline può battere none imponendo scadenze rigide e prevenendo le occasionali richieste in ritardo.
Modifica e ottimizzazione dei parametri dello scheduler
Sia la commutazione degli scheduler che la regolazione dei loro parametri avvengono tramite sysfs, senza che sia necessario riavviare il sistema per testare una modifica.
Cambio dello scheduler attivo
Verificare cosa è disponibile per un dispositivo, dove il valore tra parentesi è quello attivo:
cat /sys/block/sda/queue/schedulerPassare a uno scheduler diverso durante l'esecuzione. Questo ha effetto immediato ma non sopravvive a un riavvio:
echo bfq | sudo tee /sys/block/sda/queue/schedulerSe bfq non è elencato, caricare prima il modulo:
sudo modprobe bfqPer rendere permanente una scelta, utilizzare una regola udev anziché il vecchio elevator= parametro del kernel, che non modifica più lo scheduler su RHEL 9 e versioni simili. Questa regola imposta mq-deadline per tutti i dischi SCSI non rotanti in /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"Ricaricala e applicala senza riavviare:
sudo udevadm control --reload-rules && sudo udevadm triggerSui sistemi basati su RHEL, i profili TuneD svolgono la stessa funzione tramite profili a livello di sistema anziché regole per singolo dispositivo.
Parametri che vale la pena ottimizzare
Ogni scheduler espone i propri parametri di regolazione in /sys/block/<device>/queue/iosched/. Per mq-deadline, le scadenze sono le leve principali. I database sensibili alla latenza su SSD SATA traggono vantaggio da scadenze più brevi:
echo 100 | sudo tee /sys/block/sda/queue/iosched/read_expire
echo 1000 | sudo tee /sys/block/sda/queue/iosched/write_expirePer bfq sui sistemi ad alta velocità di trasmissione, disabilitare l'euristica di latenza aumenta la velocità di trasmissione:
echo 0 | sudo tee /sys/block/sda/queue/iosched/low_latency
echo 0 | sudo tee /sys/block/sda/queue/iosched/slice_idle| Scheduler | Parametro | Predefinito | Obiettivo di ottimizzazione |
|---|---|---|---|
mq-deadline | read_expire | 500 ms | Più basso per una risposta di lettura più veloce |
mq-deadline | write_expire | 5000 ms | Ridurre per diminuire la latenza di scrittura |
mq-deadline | writes_starved | 3 | Aumentare per carichi con molte operazioni di lettura |
mq-deadline | fifo_batch | 16 | Impostare su 1 per la latenza minima |
bfq | low_latency | 1 | Impostare su 0 per la massima velocità effettiva |
bfq | slice_idle | 8 ms | Impostare su 0 per SSD o RAID |
bfq | strict_guarantees | 0 | Impostare su 1 per una condivisione rigorosa della larghezza di banda |
Per l'hosting condiviso, BFQ si abbina bene con cgroups v2. L'assegnazione dei io.weight valori consente, ad esempio, di assegnare a un processo di database una quota di I/O dieci volte superiore a quella di un processo di backup, in modo che le attività in background non possano soffocare il traffico interattivo. Qualunque modifica si apporti, il costo per richiesta più elevato di BFQ si accumula su sistemi con elevata latenza della CPU e alto numero di IOPS, quindi è consigliabile eseguire un benchmark prima di procedere.
Verifica delle prestazioni dopo l'ottimizzazione
Acquisite sempre un dato di riferimento prima di apportare qualsiasi modifica. Senza di esso, non avrete modo di sapere se una modifica ha avuto effetto.
fio è lo strumento standard per questo. Riproduce specifici modelli di carico di lavoro attraverso le impostazioni di dimensione del blocco, profondità della coda e motore I/O. Eseguire sempre --direct=1 in modo che bypassi la cache di pagina e misuri direttamente lo scheduler e il dispositivo anziché le letture memorizzate nella cache. Adattare il test al carico di lavoro reale:
| Carico di lavoro | Parametri fio |
|---|---|
| Database OLTP | --rw=randread --bs=4k --iodepth=32 --direct=1 |
| Data warehouse | --rw=read --bs=1m --iodepth=32 --direct=1 |
| Write-ahead / log di redo | --rw=write --bs=4k --iodepth=1 --direct=1 |
| Archiviazione a oggetti | --rw=randrw --bs=64k --iodepth=64 --direct=1 |
Esegui lo stesso test con iodepth valori da 1 a 256 per individuare il punto di saturazione del dispositivo, ovvero il livello oltre il quale gli IOPS smettono di aumentare e la latenza registra picchi. Per il monitoraggio in tempo reale dopo una modifica, iostat -x 1 riporta le metriche che contano: r_await e w_await per la latenza di completamento in lettura e scrittura, aqu-sz per la profondità media della coda e %util per l’utilizzo del dispositivo. Quando %util si avvicina al 100%, l'hardware rappresenta il limite e nessuna modifica allo scheduler sarà d'aiuto.
Per separare il costo del software da quello dell'hardware, esegui blktrace con btt. Questo comando suddivide la latenza in Q2D, il tempo trascorso nella coda del software, e D2C, il tempo impiegato dal dispositivo per soddisfare la richiesta. Se Q2D è dominante, lo scheduler è il tuo collo di bottiglia. Se D2C è dominante, lo è l'hardware.
Una cosa da tenere a mente quando si leggono i risultati: la scelta dello scheduler influenza principalmente la coda della distribuzione della latenza, non la mediana. Passare da none a mq-deadline su NVMe potrebbe aumentare la latenza mediana di pochi microsecondi, riducendo però della metà la latenza p99 e p999. Per i servizi rivolti agli utenti vincolati da SLA, questo compromesso vale quasi sempre la pena, ed è per questo che misurare la latenza di coda, anziché il throughput medio, è lo scopo dell'esercizio.
Scegliere lo scheduler giusto
L'ottimizzazione dello scheduler consiste nell'adattare l'algoritmo all'hardware e al modello di accesso, per poi verificarne l'efficacia tramite misurazioni. In breve:
- NVMe: utilizzare
nonee lasciare che sia il firmware a gestire l'accodamento. - SSD SATA e HDD con I/O misto: utilizzare
mq-deadlineper una latenza prevedibile. - Host condivisi o multi-tenant: utilizzare
bfqper evitare che un carico di lavoro metta a dura prova gli altri. - Monitorate la latenza di coda, non quella mediana: le modifiche dello scheduler si manifestano a p99 e p999, quindi è quello che va misurato.
- Rendilo persistente: usa le regole udev o TuneD, mai il parametro
elevator=.
Ottenere il massimo da qualsiasi scheduler inizia con un hardware in grado di stare al passo. Se avete bisogno di server basati su NVMe progettati per carichi di lavoro ad alta produttività e bassa latenza, scoprite le opzioni VPS di FDC.
Perché è importante avere un VPS potente e senza contatore
Un VPS non misurato offre una larghezza di banda forfettaria a una velocità di porta fissa. Come si differenzia dai piani con contatore, quando conviene e cosa controllare prima dell'acquisto.
7 min di lettura - 9 maggio 2025
Gestione della memoria in Linux: Swap, OOM Killer e Cgroups
12 min di lettura - 31 maggio 2026

Avete domande o avete bisogno di una soluzione personalizzata?
Opzioni flessibili
Portata globale
Distribuzione immediata
Opzioni flessibili
Portata globale
Distribuzione immediata