NVMe o SSD SATA su VPS: fa davvero differenza?
NVMe riduce latenza e aumenta gli IOPS, ma su un VPS contano hypervisor e vicini. Scopri cosa misurare davvero con fio prima di scegliere.
NVMe è importante su un VPS?
NVMe è importante su un VPS quando il software esegue molte letture e scritture di piccole dimensioni e attende il completamento di ogni operazione. La differenza è minima per un sito che distribuisce pagine dalla cache o per un programma che trascorre la maggior parte del tempo in attesa della rete. Il tipo di supporto è solo uno dei fattori. L’hypervisor che gestisce l’accesso al disco e gli altri guest che condividono lo stesso host determinano il limite effettivo delle prestazioni.
Cosa cambia con NVMe e cosa non cambia
NVMe (non-volatile memory express) non è un tipo di memoria flash. È il protocollo e il collegamento usati per accedere alla memoria flash. Un dispositivo NVMe utilizza le linee PCIe (peripheral component interconnect express) e comunica tramite NVMe. Un SSD SATA (serial ATA) utilizza un collegamento SATA e comunica tramite AHCI (advanced host controller interface). I chip di memoria che contengono i dati possono essere identici in entrambi i casi.
Le differenze sono due, e riguardano entrambe il percorso dei comandi, non il supporto di archiviazione.
Code. AHCI mette a disposizione del kernel una coda di comandi che contiene 32 comandi. NVMe consente migliaia di code, in pratica una per core della CPU, ciascuna molto più profonda di 32 elementi. Un processo che legge un blocco alla volta non rileva questa differenza. Un database con 64 letture simultanee sì: su SATA la 33ª richiesta deve attendere uno slot nella coda prima che il dispositivo possa anche solo riceverla, mentre il dispositivo NVMe le accetta tutte e le elabora contemporaneamente.
Larghezza del collegamento. Un collegamento SATA III funziona a 6 Gbit/s, cioè circa 550 MB/s di dati effettivi dopo l'overhead del protocollo. Questo è un limite massimo fisso, indipendentemente dalla memoria flash collegata. Quattro linee PCIe trasferiscono diversi gigabyte al secondo, quindi il collegamento non è più il collo di bottiglia.
La latenza è l'aspetto su cui le aspettative sono spesso errate. Con queue depth 1, cioè una sola richiesta in transito, un SSD SATA risponde a una lettura 4k in circa 100-150 microsecondi. NVMe risponde in circa 80-100 microsecondi. Entrambi sono veloci e nessuna applicazione rileverà la differenza con una sola richiesta. Il divario emerge con la concorrenza. Queue depth, cioè il numero di richieste contemporaneamente in transito, è il parametro che determina se i due supporti si comportano in modo simile o molto diverso.
Lo storage a blocchi su rete appartiene a una terza categoria, con caratteristiche fisiche diverse. Una scrittura attraversa la rete fino a un cluster di storage e viene confermata solo quando il cluster l'ha acquisita, quindi la latenza si misura in millisecondi anziché in microsecondi. In cambio di questa latenza si ottiene durabilità: il volume continua a esistere anche se l'host a cui è collegato viene sostituito e può essere sottoposto a snapshot e ridimensionato.
Valori pubblicati tipici: NVMe, SSD SATA e storage di rete
The data behind this chart
[
{
"disk": "Local NVMe SSD",
"iops_4k_read": "184,000",
"p99_latency_ms": 0.4,
"seq_read_mbps": "3,400"
},
{
"disk": "Local SATA SSD",
"iops_4k_read": "90,000",
"p99_latency_ms": 1.2,
"seq_read_mbps": "550"
},
{
"disk": "Network block storage",
"iops_4k_read": "12,500",
"p99_latency_ms": 6.5,
"seq_read_mbps": "250"
}
]Un dispositivo NVMe locale viene comunemente indicato con 184,000 IOPS di lettura casuale 4k (operazioni di input/output al secondo) a una profondità di coda pari a 32. Lo stesso test su un SSD SATA viene indicato intorno a 90,000, limitato dalla singola coda AHCI e dal collegamento a 6 Gbit/s. Lo storage a blocchi di rete è generalmente limitato dal provider e non dall'hardware; 12,500 è un limite massimo documentato comune.
La latenza esprime lo stesso risultato nell'unità che gli utenti percepiscono. La latenza di lettura p99, cioè quella dell'1% più lento delle richieste, è di circa 0.4 ms su NVMe locale e 1.2 ms su SATA. Quando nel percorso è presente una rete, sale a 6.5 ms, oltre dieci volte il valore dell'NVMe.
Le letture sequenziali mostrano la differenza maggiore, ma sono anche il dato meno utile: 3,400 MB/s contro 550 MB/s. Quasi nessun server legge un file di grandi dimensioni dall'inizio alla fine alla massima velocità. Le colonne relative alle operazioni casuali e alla latenza descrivono meglio il comportamento reale di un database, di una coda di posta o di un package manager.
Da dove provengono questi valori e perché i tuoi saranno diversi
Le 3 righe riportano i valori delle schede tecniche dei vendor per i dispositivi locali e i limiti documentati per volume dello storage di rete, aggiornati a luglio 2026 e arrotondati. Presuppongono una dimensione dei blocchi di 4k, letture casuali, una profondità di coda pari a 32 e un singolo job, ovvero il tipo di test pubblicato dai vendor. Il tuo VPS è una guest su un host condiviso, quindi lo stesso test sul tuo sistema normalmente restituisce valori inferiori, che possono variare tra un'esecuzione e l'altra. Interpreta queste righe come indicazione della differenza tra le tre categorie, non come un obiettivo da raggiungere.
Quali carichi di lavoro risentono del disco
Una sola regola spiega tutti i casi: un carico di lavoro risente del disco solo quando deve attendere il disco. Linux mantiene in RAM i dati dei file usati di recente, nella page cache, quindi la seconda lettura di un file non raggiunge mai lo storage. Se il working set, cioè i dati effettivamente in uso, entra nella RAM, dopo il primo passaggio le letture diventano letture dalla memoria. Le scritture sono diverse. Ogni scrittura che l'applicazione forza con fsync() deve essere presente su uno storage stabile prima che l'applicazione possa continuare.
Carichi che eseguono il commit. PostgreSQL, MySQL e SQLite chiamano fsync() o fdatasync() durante il commit, e ogni commit attende la risposta del dispositivo. Il numero di commit al secondo di una connessione è quindi determinato dalla latenza di scrittura, non dalla larghezza di banda. Un dispositivo che esegue il flush in 0.2 ms consente molti più commit al secondo rispetto a uno che impiega 5 ms, e nessuna quantità di throughput può modificare questo limite. MySQL lo indica nel log degli errori quando il flush non riesce a tenere il passo:
[Note] InnoDB: page_cleaner: 1000ms intended loop took 4589ms. The settings might not be optimal.PostgreSQL lo segnala nelle righe relative ai checkpoint, dove un valore elevato di sync= indica che il flush è stato lento:
LOG: checkpoint complete: wrote 8192 buffers (25.0%); write=27.694 s, sync=11.207 s, total=39.001 sCarichi che accedono a molti file piccoli. Ogni file comporta operazioni sui metadati che una singola lettura sequenziale di grandi dimensioni non richiede. npm install, git clone di un repository di grandi dimensioni, l'estrazione di immagini container, un archivio di posta Maildir e un backup che attraversa un albero di grandi dimensioni trascorrono la maggior parte del tempo in accessi casuali di piccole dimensioni. Un job di backup restic su un VPS legge e calcola l'hash di ogni file che non ha già visto, quindi la durata complessiva di un backup su un milione di file segue da vicino la latenza delle letture casuali. Lo stesso vale per du -sh, che legge soltanto i metadati.
Anche i database che superano la capacità della RAM rientrano in questa categoria. Quando l'indice non entra più nella page cache, ogni ricerca diventa una lettura casuale e il disco torna a essere parte del percorso critico.
Quali workload non risentono del disco
Un blog o il sito di una piccola azienda. Le pagine sono di piccole dimensioni e, dopo la prima richiesta, la page cache le contiene tutte. Il limite è la CPU necessaria per il rendering oppure la larghezza di banda richiesta dagli asset. Uno stack LAMP su Ubuntu 24.04 che serve un sito con poco traffico genera un numero minimo di operazioni di I/O su disco una volta entrato a regime.
Streaming multimediale. Uno stream 4K a 40 Mbit/s legge 5 MB/s. Dieci stream leggono 50 MB/s, una velocità che anche lo storage a blocchi di rete riesce a gestire senza difficoltà. Un server multimediale Jellyfin su un VPS è limitato dalla larghezza di banda in uscita disponibile sulla rete e dalla CPU durante la transcodifica, non dal supporto di storage.
Inferenza con modelli locali. Eseguire Ollama su un VPS per self-hostare un LLM legge il file del modello una volta, quindi opera in RAM. NVMe riduce il tempo di caricamento di un modello da 20 GB da minuti a secondi. Non modifica il numero di token al secondo, che dipende dalla larghezza di banda della memoria e dalla CPU.
Qualsiasi workload in attesa di un servizio esterno. Un worker che impiega 800 ms per job in una richiesta HTTP non diventa più veloce con un disco migliore.
Perché l’hypervisor conta quanto il supporto
Non si comunica direttamente con il dispositivo. Si comunica con un disco virtuale presentato dall’hypervisor, in genere tramite virtio, e diverse decisioni a quel livello contano più della differenza tra NVMe e SATA.
Dal guest non è possibile vedere il supporto. lsblk -d -o NAME,ROTA,SIZE,MODEL mostra vda con il modello vuoto, perché virtio non trasferisce l’identità dell’unità. cat /sys/block/vda/queue/rotational restituisce ciò che l’hypervisor pubblicizza, quindi un valore pari a 0 non dimostra che il supporto sia flash. nvme list, incluso nel pacchetto nvme-cli, nella maggior parte dei VPS non elenca nulla, anche quando l’host contiene numerose unità NVMe, perché il disco è un dispositivo virtio e non un dispositivo NVMe. Un piano che indica NVMe descrive in genere i dispositivi presenti sull’host. Il volume può comunque essere collegato tramite rete.
La modalità di cache dell’host modifica i risultati più del supporto. Con il caching writeback sull’host, un guest fsync() può restituire il risultato non appena l’host ha i dati nella propria RAM. Questo produce un risultato di benchmark che nessun dispositivo fisico potrebbe raggiungere. Significa anche che un arresto anomalo dell’host può causare la perdita di scritture che il database considera già sicure. Con la modalità di cache none, i valori sono inferiori e più rappresentativi.
Limiti e crediti burst. Molti provider impongono un limite agli IOPS per volume o per piano e molti volumi di rete utilizzano una disponibilità burst. La disponibilità burst è un insieme di crediti: il volume opera a velocità elevata finché i crediti sono disponibili, poi scende a una baseline molto più bassa. Il sintomo è facile da riconoscere. Un’importazione o un ripristino procede rapidamente per alcuni minuti, poi rallenta bruscamente e rimane lento, senza modifiche alla configurazione. I crediti sono esauriti.
Altri guest. Su un host condiviso, la latenza del disco varia in funzione delle attività degli altri guest. Per questo è necessario eseguire più di una misurazione. Eseguire lo stesso test al mattino e di nuovo alla sera, quindi confrontare la dispersione dei risultati. Su un host sotto carico, la differenza tra due esecuzioni sullo stesso volume è spesso maggiore della differenza pubblicizzata tra due supporti.
Come misurare lo spazio disco effettivamente disponibile sul VPS
Installare fio, il benchmark IO standard, ed eseguire la misurazione. Prima, considerare tre aspetti. Il test crea un file, quindi utilizza spazio su disco e incide su qualsiasi limite IOPS incluso nella fatturazione. Mantenere brevi le esecuzioni. Non eseguire il test con una profondità della coda massima su un volume che gestisce traffico in produzione, perché si contenderebbe le risorse con l'applicazione.
sudo apt update && sudo apt install -y fio ioping sysstat
cd /var/tmpLetture casuali con profondità della coda pari a 32, il valore indicato dai provider:
fio --name=randread --filename=fio.test --size=1G --bs=4k --rw=randread \
--ioengine=libaio --direct=1 --iodepth=32 --numjobs=1 \
--runtime=30 --time_based --group_reportingLa riga importante inizia con read:
read: IOPS=184k, BW=719MiB/s (754MB/s)(21.1GiB/30001msec)--direct=1 bypassa la page cache del guest, quindi il risultato descrive il dispositivo anziché la RAM. Se si omette, si misura la memoria, che restituisce un valore irraggiungibile da qualsiasi disco. Usare --size=4G o un valore superiore se lo spazio lo consente, perché un file da 1G può rimanere interamente nella cache dell'host e rendere il risultato più favorevole.
La profondità della coda pari a 1 mostra la latenza effettiva, cioè quella percepita da un processo a thread singolo:
fio --name=lat --filename=fio.test --size=1G --bs=4k --rw=randread \
--ioengine=libaio --direct=1 --iodepth=1 --runtime=30 --time_basedIl test dei commit permette di prevedere il comportamento del database. Scrive 4k e chiama fdatasync() dopo ogni scrittura, quindi il valore della velocità include il flush:
fio --name=commit --filename=fio.test --size=1G --bs=4k --rw=randwrite \
--ioengine=psync --fdatasync=1 --runtime=30 --time_based
rm -f fio.testIl valore IOPS ottenuto da questa esecuzione è vicino al numero massimo di piccole transazioni al secondo che una connessione al database può eseguire con commit, perché un commit attende lo stesso flush.
Per una misurazione rapida senza fio:
ioping -c 20 .--- . (ext4 /dev/vda1) ioping statistics ---
19 requests completed in 4.13 ms, 76 KiB read, 4.60 k iops, 17.9 MiB/s
min/avg/max/mdev = 174.2 us / 217.6 us / 386.1 us / 51.3 usIl valore mdev, cioè la deviazione media, è importante quanto la media. Una deviazione elevata su un sistema inattivo indica che il backend di storage è condiviso e sotto carico.
Come leggere il risultato
A luglio 2026, questi valori sono ragionevoli per un piccolo VPS. Decine di migliaia di IOPS in lettura casuale da 4k con queue depth 32, insieme a una latenza con queue depth 1 inferiore a circa 0.3 ms, sono compatibili con lo storage flash locale. Una latenza con queue depth 1 di diversi millisecondi indica un percorso di rete, indipendentemente dal nome del piano. Letture sequenziali che si fermano vicino a 550 MB/s indicano la presenza di un collegamento SATA. Un valore molto superiore alle prestazioni di qualsiasi singolo dispositivo indica che nel percorso è presente una cache, quasi sempre sull'host.
Per vedere in che modo il carico di lavoro attivo sta utilizzando il disco:
iostat -x 1 3
vmstat 1 5
cat /proc/pressure/ioNell'output di iostat -x, leggi r_await e w_await, cioè i millisecondi medi durante i quali una richiesta è rimasta in attesa, e aqu-sz, cioè la lunghezza media della coda. Ignora %util su un disco virtuale. Questo valore indica la percentuale di tempo in cui almeno una richiesta era in sospeso, ma non fornisce informazioni sulla saturazione di un dispositivo che gestisce molte richieste contemporaneamente. Per questo motivo, un valore %util pari a 100 insieme a un valore r_await di 0.2 ms indica un disco occupato ma in condizioni normali. In vmstat, la colonna wa indica la percentuale di tempo CPU trascorsa in attesa di IO. Se /proc/pressure/io è disponibile nel kernel, il relativo valore some avg10= indica la quota degli ultimi 10 secondi durante la quale almeno un task era bloccato in attesa di IO. È il dato più diretto per stabilire se lo storage costituisce il collo di bottiglia.
Come si presenta una VPS vincolata dal disco
Un load average elevato con CPU inattiva e un valore elevato di wa in vmstat indica che i processi sono in coda in attesa del disco. Il segnale più chiaro del kernel è questo messaggio in dmesg -T:
INFO: task jbd2/vda1-8:194 blocked for more than 120 seconds.Quella riga viene registrata perché un thread del kernel ha atteso oltre due minuti una risposta dallo storage; il watchdog delle attività bloccate ha quindi registrato l’evento. jbd2 è il thread del journal di ext4, quindi era in attesa l’intero filesystem, non un singolo programma che si comportava in modo anomalo. Su una VPS, questo indica generalmente un problema del backend di storage o l’esaurimento della quota di IOPS.
Anche i sintomi dell’applicazione seguono lo stesso schema. Il tempo di risposta mediano resta accettabile, mentre le richieste più lente formano una lunga coda di valori elevati, perché solo le richieste che accedono al disco subiscono il ritardo. apt upgrade resta su Unpacking per diversi minuti, perché dpkg esegue il flush dei dati durante la scrittura. git status in un repository di grandi dimensioni richiede alcuni secondi. Si tratta di costi relativi ai metadati e alle operazioni di flush, quindi una maggiore larghezza di banda non risolverebbe il problema.
Cosa fare quando il limite è il disco
Acquista RAM prima di acquistare IOPS. Se il working set entra nella page cache, le letture non raggiungono più il disco. Raddoppiare la memoria spesso offre prestazioni migliori rispetto al passaggio a una classe di storage più veloce e, di solito, costa meno.
Riduci il numero di flush quando i dati lo consentono. In PostgreSQL, synchronous_commit = off consente al commit di restituire il controllo prima che la scrittura venga completata sul disco. Se il server si arresta, puoi perdere l'ultima frazione di secondo delle transazioni. Il database non viene danneggiato, perché il write-ahead log viene comunque scritto in ordine. Questa scelta è adatta a una copia per l'analisi, ma non ai pagamenti. In MySQL, innodb_flush_log_at_trx_commit = 2 applica lo stesso compromesso.
Raggruppa i file piccoli. Un trasferimento o un backup di un milione di file piccoli è dominato dal costo per file. Su storage con latenza elevata, creare prima un archivio e trasferire un unico stream è quindi più veloce che copiare l'albero un file alla volta.
Mantieni operativo discard sui volumi thin. Con lo storage thin provisioned, il backend non sa che un blocco è libero finché il filesystem non lo segnala. Un volume che non esegue mai il trim perde gradualmente prestazioni in scrittura. Ubuntu fornisce un timer settimanale:
systemctl status fstrim.timer
sudo fstrim -avfstrim -av mostra i byte sottoposti a trim per ogni punto di mount. Un messaggio che indica che l'operazione discard non è supportata significa che il disco virtuale non inoltra discard all'host. Non c'è quindi nulla da correggere.
Evita la regolazione dello scheduler I/O. Su un disco virtio, cat /sys/block/vda/queue/scheduler mostra di solito già none, mentre la pianificazione effettiva avviene sull'host, al quale non hai accesso. Evita anche noatime: Ubuntu esegue il mount con relatime per impostazione predefinita, evitando già quasi tutte le scritture di atime.
Scegliere un piano
Scegli NVMe quando sul server esegui un database, un mail server, un CI runner o una build con molte dipendenze. Non pagare un sovrapprezzo per un sito con contenuti in cache o per un’applicazione il cui tempo di esecuzione dipende da chiamate esterne. Se non sei sicuro, probabilmente il disco non è il collo di bottiglia: nella maggior parte dei piccoli carichi di lavoro VPS, il limite raggiunto per primo è la RAM o la larghezza di banda.
Esegui le misurazioni il primo giorno, mentre segui i primi dieci minuti su un nuovo VPS, e salva l’output in un file. Una baseline ti permette in seguito di dimostrare che l’host è diventato più lento, invece di attribuire il problema al tuo codice. Preferisci provider che dichiarano per iscritto la classe di storage e l’eventuale limite di IOPS. Se un piano dichiara NVMe, ma una lettura con queue depth 1 richiede 4 ms, stai usando storage di rete su un host dotato di NVMe. È un prodotto legittimo da vendere, ma non è la stessa cosa che acquistare storage NVMe locale.
FAQ
NVMe è sempre più veloce di un SSD SATA su un VPS?
No. Con una queue depth pari a 1, i due dispositivi offrono prestazioni simili, circa da 80 a 150 microsecondi per una lettura 4k, e un programma single-threaded non rileva differenze. NVMe offre prestazioni migliori quando molte richieste sono in corso contemporaneamente, perché AHCI mette a disposizione una coda con una profondità di 32 comandi, mentre NVMe offre migliaia di code più profonde. Su un host condiviso, il carico degli altri guest può modificare la latenza più del supporto stesso. Misura quindi il tuo volume con fio invece di basarti sul nome del piano.
Come verifico se il mio VPS usa realmente NVMe?
Non puoi verificarlo direttamente, perché virtio nasconde il dispositivo fisico. lsblk mostra vda senza una stringa del modello, nvme list non restituisce nulla e /sys/block/vda/queue/rotational indica soltanto ciò che dichiara l’hypervisor. Misura invece il comportamento. Una lettura random 4k con queue depth pari a 1 e una latenza inferiore a circa 0.3 ms indica flash locale. Una latenza di diversi millisecondi indica che nel percorso è presente un passaggio sulla rete. Letture sequenziali che si fermano vicino a 550 MB/s indicano un collegamento SATA.
NVMe rende più veloce il caricamento del mio sito?
Di norma no. Dopo la prima richiesta, Linux serve i file dalla page cache in RAM, quindi il disco resta inattivo. Su un VPS di piccole dimensioni, la velocità della pagina dipende normalmente dal tempo CPU dell’applicazione e dalla banda disponibile. Il disco torna nel percorso critico se il sito scrive a ogni richiesta, per esempio nel caso di un carrello basato su database che esegue spesso commit, perché ogni commit attende il completamento di un flush.
Qual è un buon risultato di fio per un VPS?
A luglio 2026, un VPS di piccole dimensioni con flash locale restituisce normalmente decine di migliaia di IOPS in lettura random 4k con queue depth pari a 32, e una latenza inferiore a 0.3 ms con queue depth pari a 1. Lo storage a blocchi di rete restituisce normalmente alcune migliaia di IOPS con una latenza di pochi millisecondi. Esegui il test 3 volte in orari diversi. Una forte variazione tra le esecuzioni fornisce più informazioni della media, perché mostra quanto gli altri guest sull’host incidano sulle tue prestazioni.
Devo mettere il database su uno storage a blocchi di rete?
Puoi farlo, e molti servizi gestiti lo fanno, ma il percorso dei commit ne risente. Ogni flush attraversa la rete, quindi una singola connessione esegue meno transazioni di piccole dimensioni al secondo rispetto a quanto farebbe su flash locale. In cambio ottieni una durabilità che sopravvive all’host. Se scegli lo storage di rete per un database con molte scritture, raggruppa le operazioni in transazioni più grandi, così un numero inferiore di flush trasferisce più righe.