Messa a punto dello scheduler I/O di Linux: mq-deadline, none, BFQ

16 min di lettura - 1 giugno 2026

hero section cover
Indice
  • Ottimizzazione dello scheduler I/O di Linux: mq-deadline, none e BFQ
  • In che modo mq-deadline, none e BFQ differiscono
  • Scegliere lo scheduler adatto al proprio carico di lavoro
  • Modifica e ottimizzazione dei parametri dello scheduler
  • Verifica delle prestazioni dopo l'ottimizzazione
  • Scegliere lo scheduler giusto
Condividi

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.

SchedulerAlgoritmoOverhead della CPUHardware ottimaleObiettivo principale
mq-deadlineLBA ordinati con scadenzeBasso (~0,7 µs/richiesta)SSD SATA, HDD, dischi virtualiBassa latenza prevedibile
noneFIFO, nessun riordinoTrascurabileSSD NVMeThroughput massimo
bfqBudget a quota proporzionaleModerato (~1,9 µs/richiesta)HDD, sistemi condivisi e desktopEquità 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 lavoroArchiviazioneSchedulerMotivo
Addestramento AI/MLSSD NVMenoneElevata velocità sequenziale; il firmware gestisce l'accodamento
Database OLTPSSD NVMenoneI/O casuale a bassa latenza; evita il sovraccarico del software
Database OLTPSSD SATAmq-deadlinePreviene lo "write starvation"; latenza di coda prevedibile
Data warehouse / OLAPNVMe / SSD velocenoneCode parallele profonde; throughput massimo
Web hosting genericoSSD SATA / HDDmq-deadlineRisposta costante per I/O misto su file di piccole dimensioni
Hosting condiviso / multi-tenantHDD / SSDbfqEquità tra gli utenti; impedisce il monopolio dell'I/O
Macchina virtuale guestvirtio-blknoneL'host esegue già la pianificazione; la doppia pianificazione comporta uno spreco di CPU
Backup / archiviazioneHDDmq-deadlineThroughput 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/scheduler

Passare 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/scheduler

Se bfq non è elencato, caricare prima il modulo:

sudo modprobe bfq

Per 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 trigger

Sui 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_expire

Per 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
SchedulerParametroPredefinitoObiettivo di ottimizzazione
mq-deadlineread_expire500 msPiù basso per una risposta di lettura più veloce
mq-deadlinewrite_expire5000 msRidurre per diminuire la latenza di scrittura
mq-deadlinewrites_starved3Aumentare per carichi con molte operazioni di lettura
mq-deadlinefifo_batch16Impostare su 1 per la latenza minima
bfqlow_latency1Impostare su 0 per la massima velocità effettiva
bfqslice_idle8 msImpostare su 0 per SSD o RAID
bfqstrict_guarantees0Impostare 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 lavoroParametri 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 none e lasciare che sia il firmware a gestire l'accodamento.
  • SSD SATA e HDD con I/O misto: utilizzare mq-deadline per una latenza prevedibile.
  • Host condivisi o multi-tenant: utilizzare bfq per 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.

Blog

In primo piano questa settimana

Altri articoli
Perché è importante avere un VPS potente e senza contatore

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

Altri articoli
background image

Avete domande o avete bisogno di una soluzione personalizzata?

icon

Opzioni flessibili

icon

Portata globale

icon

Distribuzione immediata

icon

Opzioni flessibili

icon

Portata globale

icon

Distribuzione immediata