Torna al blog
31 agosto 2026Sergei Solod8 min di lettura

Il mio VPS REGXA mostrava il 94% di CPU steal anche senza traffico

Indagando su gravi problemi di prestazioni di un VPS KVM REGXA ho rilevato il 92–94% di CPU steal, richieste localhost da diversi secondi, code di connessioni in crescita e HTTP 504 dopo più di due minuti. Dopo aver rimosso tutto il traffico di produzione, il CPU steal è salito al 94,17% e REGXA ha poi attribuito il problema alla contesa di risorse sulla propria infrastruttura condivisa.

REGXAVPSLinuxCPU stealvirtualizzazione

Non sto scrivendo questa storia come recensione negativa di REGXA e non sto cercando di dire a qualcuno se dovrebbe o meno comprare un VPS da loro. È semplicemente una delle mie giornate da sviluppatore.

Ho spostato un workload normale su un VPS KVM con 2 vCPU, 2 GB di RAM e 60 GB NVMe. Nginx era attivo. Il backend era attivo. Eppure la macchina si comportava come se fosse pesantemente sovraccarica: le richieste si accumulavano, TLS diventava lento, le connessioni rimanevano aperte e alcune richieste finivano con HTTP 504 dopo più di due minuti.

La contabilità della CPU ha cambiato l’indagine

La mia prima ipotesi era ovvia: qualcosa dentro il VPS stava consumando il processore. Poi ho eseguito mpstat.

Average CPU steal: 92.58%
CPU 0 steal: 90.62%
CPU 1 steal: 94.57%
CPU user: 4.02%
CPU system: 1.47%
CPU iowait: 0.41%
CPU idle: 0.53%

I singoli campioni mostravano ripetutamente circa l’89–98% di steal. Anche la pressione CPU era estrema:

CPU PSI some avg10: 79.47
CPU PSI some avg60: 75.32
CPU PSI some avg300: 76.31
Load average: 5.85 / 5.75 / 5.73

Era una macchina con appena due vCPU. Linux aveva processi runnable in attesa di CPU. Il numero importante non era il normale consumo CPU delle applicazioni, ma %steal.

CPU alta e CPU steal sono problemi diversi

Se fosse stata davvero la mia applicazione a saturare il processore, mi sarei aspettato valori elevati di user o system. Invece il VPS appariva più o meno così:

user: 4%
system: 1%
steal: 93%

Il CPU steal è il tempo in cui una CPU virtuale è pronta a essere eseguita ma l’hypervisor non la schedula. Quindi, quando dico che al VPS veniva sottratto tempo CPU, lo intendo in questo preciso senso tecnico di virtualizzazione. Non posso dimostrare che REGXA abbia deliberatamente riassegnato ad altri clienti core fisici che erano esclusivamente miei, né posso dedurre intenzionalità dalle metriche del guest. Posso però dimostrare che il guest aveva ripetutamente lavoro pronto e non riceveva tempo di scheduling CPU.

Ho rimosso tutto il traffico di produzione

Restava un’obiezione ragionevole: forse era il mio workload a provocare il problema. Ho quindi eliminato quella variabile. Ho spostato il carico attivo altrove, fermato il traffico di produzione verso questo VPS, lasciato svuotare le code e ripetuto la misurazione.

Average CPU steal: 94.17%
CPU 0 steal: 95.56%
CPU 1 steal: 92.83%
CPU user: 1.95%
CPU system: 0.59%
CPU iowait: 0.59%
CPU idle: 2.18%

Il risultato è peggiorato. I singoli campioni di vmstat mostravano ancora 91–98% di steal e fino a 15 processi runnable attendevano la CPU. La combinazione più importante era:

user: 1.95%
system: 0.59%
steal: 94.17%

Le mie applicazioni ormai facevano quasi nulla, ma la VM continuava a perdere quasi tutto il proprio tempo di scheduling. Il normale carico di produzione non era più una spiegazione credibile.

Anche localhost era diventato assurdamente lento

Ho testato anche HTTPS tramite 127.0.0.1, eliminando dall’esperimento DNS pubblico, il mio ISP, la distanza geografica e il percorso di rete esterno.

Sotto traffico, quattro tentativi HTTPS localhost su dieci fallivano durante il TLS handshake. Le richieste riuscite impiegavano 29,30, 22,77, 12,25, 11,87, 11,12 e 9,40 secondi. Alcuni TLS handshake da soli richiedevano circa nove secondi.

Dopo la rimozione del traffico di produzione, localhost è migliorato ma è rimasto instabile: 0,061, 0,745, 0,830, 0,873, 1,010, 1,117, 1,121, 2,188 e 3,355 secondi. La stessa operazione locale poteva richiedere circa 61 ms una volta e oltre 3,3 secondi al tentativo successivo.

Il resto dello stack mostrava le conseguenze

A un certo punto ho osservato circa 450 connessioni established, 122 connessioni orphaned, 110 FIN-WAIT-1 e 33 CLOSE-WAIT. La listen queue del backend locale ha raggiunto circa 14–15, mentre quella HTTPS è arrivata a circa 40.

Nginx ha registrato HTTP 504 dopo 142,857, 138,902, 135,064, 129,819 e 128,657 secondi. Altre richieste sono rimaste aperte per circa 67–130 secondi. Ho visto anche secure-connect timeout intorno a 35–41 secondi, database network timeout e operazioni TLS ritardate.

Presi singolarmente, questi sintomi potevano sembrare problemi separati di Nginx, database, rete o backend. Ma aumentare i timeout non crea tempo CPU che l’hypervisor non schedula.

RAM e disco non spiegavano il problema

Il VPS aveva ancora circa 1,0–1,1 GiB di RAM disponibile, quasi nessun utilizzo di swap, nessun evento OOM e nessuna attività dell’OOM killer. Il filesystem era pieno solo per circa il 20%, con circa 44 GB disponibili. L’I/O wait rimaneva sotto l’1% durante le misurazioni CPU importanti.

La memoria non era esaurita, il disco non era pieno e le mie applicazioni non stavano consumando la CPU mancante. La metrica dominante rimaneva %steal.

Un VPS KVM sano appariva completamente diverso

Ho eseguito lo stesso tipo di diagnostica su un altro VPS KVM che serviva realmente traffico normale:

Average CPU steal: 0.02%
CPU idle: 87.86%
CPU PSI avg10: 0.29
CPU PSI avg60: 0.63
CPU PSI avg300: 0.49
Load average: 0.47 / 0.33 / 0.14

Le sue dieci richieste HTTPS localhost completavano in circa 37–69 ms. Più tardi, su un altro VPS di produzione realmente impegnato, ho misurato 61,71% di CPU user, 5,08% di CPU system, 24,09% idle e appena 0,13% steal.

È questa la distinzione che oggi mi interessa. Un VPS può essere occupato perché il mio software sta davvero usando il processore. È molto diverso da un guest che trascorre oltre il 90% del tempo CPU misurato aspettando l’hypervisor.

REGXA ha infine confermato la contesa sull’infrastruttura

Dall’interno della VM potevo misurare il guest, ma non vedere l’host fisico, la configurazione dello scheduler, le CPU quota o le VM vicine. REGXA poteva farlo.

Alla fine il supporto mi ha detto che il VPS era ospitato su una shared CPU infrastructure, che le risorse CPU erano condivise tra più virtual machine e che le prestazioni potevano variare in funzione del carico del nodo fisico. Mi hanno anche comunicato che l’infrastruttura di Frankfurt stava vivendo una domanda particolarmente elevata e hanno esplicitamente attribuito il mio CPU steal elevato a resource contention on the underlying infrastructure.

Hanno inoltre spiegato di non poter cambiare CPU quota o scheduling policy né dedicare risorse CPU aggiuntive a quel VPS condiviso sull’infrastruttura attuale. La soluzione tecnica proposta era spostarlo in una località con utilizzo inferiore.

Questo era difficile da conciliare con il linguaggio che avevo visto su dedicated CPU cores e guaranteed resources. Non posso vedere l’esatta configurazione dell’host, quindi non posso dire se il meccanismo immediato fosse CPU overcommitment, quota, scheduler weighting, throttling o una combinazione. Non posso neanche dimostrare intenzionalità. Non è necessario: Linux ha mostrato stabilmente 92–94% di steal e REGXA stessa ha attribuito il valore elevato alla contesa sulla propria infrastruttura condivisa.

Anche ottenere il rimborso ha richiesto ulteriore insistenza

Una volta chiarito il problema infrastrutturale, non volevo continuare a spostare il VPS e testare altri nodi. Volevo annullare il servizio e riavere i miei soldi.

Inizialmente mi è stata offerta solo una somma parziale, e il rimborso proposto sarebbe finito nel saldo del mio account REGXA invece che sulla carta con cui avevo pagato. Per me il credito presso il provider non equivale a un rimborso quando sto cercando di lasciare il servizio.

Ho quindi continuato a rispondere chiedendo che il 100% del pagamento tornasse sul metodo di pagamento originale. Alla fine REGXA ha accettato e ha restituito l’intero importo al metodo di pagamento iniziale, descrivendo il rimborso completo come un’eccezione.

Apprezzo il fatto che alla fine abbiano restituito tutto. Ma dover continuare a insistere per la soluzione economica dopo che il supporto aveva già riconosciuto la contesa infrastrutturale fa comunque parte della mia esperienza.

La lezione che mi è rimasta

L’errore più facile sarebbe stato continuare a ottimizzare l’applicazione. Avrei potuto cambiare Nginx, aumentare i timeout, ridurre la concurrency, aggiungere retry, indagare MongoDB o riscrivere il backend. Alcune modifiche avrebbero forse cambiato singoli sintomi. Nessuna avrebbe risposto alla domanda importante: perché il CPU steal era superiore al 90%?

Ora non mi fermo più al fatto che SSH funzioni, Nginx parta e un health endpoint risponda 200. Su un VPS nuovo controllo anche %user, %system, %iowait, %idle, %steal, CPU PSI, run queue e latenza localhost.

E quando qualcosa sembra sospetto, rimuovo il workload e misuro di nuovo. In questo caso è stato il test che ha prodotto il dato più chiaro dell’intero incidente:

CPU user: 1.95%
CPU system: 0.59%
CPU steal: 94.17%

Non sto dicendo che ogni VPS REGXA si comporti così. Ho testato un VPS e documentato ciò che è successo a quella macchina. Ma in quel caso le prove erano insolitamente chiare: le mie applicazioni consumavano pochissima CPU, mentre Linux mostrava che la grande maggioranza del tempo CPU virtuale andava persa nell’attesa dello scheduling dell’hypervisor. REGXA ha successivamente attribuito proprio quel comportamento alla contesa di risorse sulla propria infrastruttura condivisa.

È per questo che lo documento. Non come voto o raccomandazione, ma semplicemente come una giornata della mia vita da sviluppatore — e come una metrica che non ignorerò mai più su un VPS.