Je n’écris pas ceci comme un avis négatif sur REGXA, et je n’essaie pas de dire aux autres s’ils devraient ou non acheter un VPS chez eux. C’est simplement une journée ordinaire de ma vie de développeur.
J’ai déplacé une charge normale sur un VPS KVM disposant de 2 vCPU, 2 GB de RAM et 60 GB de NVMe. Nginx tournait. Le backend tournait. Pourtant, la machine se comportait comme si elle était massivement saturée : les requêtes s’accumulaient, TLS devenait lent, les connexions restaient ouvertes et certaines requêtes finissaient par renvoyer HTTP 504 après plus de deux minutes.
La comptabilité CPU a changé l’enquête
Ma première hypothèse était évidente : quelque chose dans le VPS consommait le processeur. J’ai alors lancé 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%
Les échantillons individuels montraient régulièrement environ 89–98 % de steal. La pression CPU était elle aussi extrême :
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
Il s’agissait d’une VM avec seulement deux vCPU. Linux avait des processus exécutables en attente de CPU. La métrique importante n’était pas l’utilisation CPU normale des applications, mais %steal.
Une forte utilisation CPU et le CPU steal sont deux problèmes différents
Si mon application consommait réellement le processeur, je m’attendrais à voir beaucoup de temps user ou system. Or le VPS ressemblait plutôt à ceci :
user: 4%
system: 1%
steal: 93%
Le CPU steal correspond au temps pendant lequel un processeur virtuel est prêt à s’exécuter mais n’est pas planifié par l’hyperviseur. Quand je dis que du temps CPU était retiré au VPS, c’est dans ce sens technique précis. Je ne peux pas prouver que REGXA a volontairement réaffecté à d’autres clients des cœurs physiques qui m’auraient été exclusivement réservés, et les métriques du système invité ne permettent pas de déduire une intention. Ce que je peux démontrer, c’est que la VM avait régulièrement du travail prêt et ne recevait pas le temps de planification CPU nécessaire.
J’ai supprimé tout le trafic de production
Une objection évidente restait possible : ma charge pouvait elle-même provoquer le problème. J’ai donc retiré cette variable. J’ai déplacé la charge active ailleurs, arrêté tout trafic de production vers ce VPS, laissé les files se vider puis répété la mesure.
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%
Le résultat a empiré. Les échantillons vmstat affichaient encore 91–98 % de steal, avec jusqu’à 15 processus exécutables en attente de CPU. La combinaison essentielle était :
user: 1.95%
system: 0.59%
steal: 94.17%
Mes applications ne faisaient presque plus rien, mais la VM perdait toujours l’essentiel de son temps de planification. La charge de production normale n’était plus une explication crédible.
Même localhost devenait absurdement lent
J’ai également testé HTTPS via 127.0.0.1, ce qui éliminait de l’expérience le DNS public, mon FAI, la distance géographique et le chemin réseau externe.
Sous trafic, quatre requêtes HTTPS localhost sur dix ont échoué pendant le handshake TLS. Les requêtes réussies ont pris 29,30, 22,77, 12,25, 11,87, 11,12 et 9,40 secondes. Certains handshakes TLS seuls ont pris environ neuf secondes.
Après retrait du trafic de production, localhost s’est amélioré mais est resté très instable : 0,061, 0,745, 0,830, 0,873, 1,010, 1,117, 1,121, 2,188 et 3,355 secondes. La même opération locale pouvait prendre environ 61 ms lors d’un essai puis plus de 3,3 secondes au suivant.
Le reste de la pile montrait les conséquences
À un moment, j’ai observé environ 450 connexions établies, 122 connexions orphelines, 110 FIN-WAIT-1 et 33 CLOSE-WAIT. La file d’écoute du backend local a atteint environ 14–15, tandis que celle de HTTPS montait à environ 40.
Nginx a journalisé des réponses HTTP 504 après 142,857, 138,902, 135,064, 129,819 et 128,657 secondes. D’autres requêtes sont restées ouvertes pendant environ 67–130 secondes. J’ai également observé des secure-connect timeouts autour de 35–41 secondes, des timeouts réseau vers la base de données et des opérations TLS retardées.
Pris séparément, ces symptômes pouvaient ressembler à plusieurs problèmes indépendants de Nginx, de base de données, de réseau ou de backend. Mais augmenter les timeouts ne crée pas le temps CPU que l’hyperviseur ne planifie pas.
La RAM et le disque n’expliquaient pas le problème
Le VPS disposait encore d’environ 1,0–1,1 GiB de RAM disponible, utilisait presque aucun swap, et ne présentait ni événement OOM ni activité de l’OOM killer. Le système de fichiers n’était rempli qu’à environ 20 %, avec près de 44 GB disponibles. L’I/O wait est resté inférieur à 1 % pendant les mesures CPU importantes.
La mémoire n’était pas épuisée, le disque n’était pas plein, et mes applications ne consommaient pas le CPU manquant. La métrique dominante restait %steal.
Un VPS KVM sain avait un comportement totalement différent
J’ai exécuté le même type de diagnostic sur un autre VPS KVM qui servait réellement du trafic normal :
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
Ses dix requêtes HTTPS locales ont toutes terminé entre environ 37 et 69 ms. Plus tard, sur un autre VPS de production réellement chargé, j’ai mesuré 61,71 % de CPU user, 5,08 % de CPU system, 24,09 % d’idle et seulement 0,13 % de steal.
C’est cette distinction qui m’importe désormais. Un VPS peut être occupé parce que mon logiciel utilise réellement le processeur. C’est très différent d’un système invité qui passe plus de 90 % du temps CPU mesuré à attendre l’hyperviseur.
REGXA a finalement confirmé la contention au niveau de l’infrastructure
Depuis la VM, je pouvais mesurer le système invité, mais pas voir l’hôte physique, la configuration du scheduler, les quotas CPU ou les VM voisines. REGXA, elle, pouvait le faire.
Le support m’a finalement indiqué que le VPS était hébergé sur une shared CPU infrastructure, que les ressources CPU étaient partagées entre plusieurs machines virtuelles et que les performances pouvaient varier selon la charge du nœud physique. Ils ont également indiqué que l’infrastructure de Frankfurt connaissait une demande particulièrement élevée et ont explicitement attribué mon CPU steal élevé à resource contention on the underlying infrastructure.
Ils ont précisé qu’ils ne pouvaient pas modifier les quotas ou les politiques de planification CPU ni attribuer davantage de ressources CPU dédiées à ce VPS partagé sur l’infrastructure actuelle. La solution technique proposée était un déplacement vers un emplacement moins chargé.
Cette explication était difficile à concilier avec le langage que j’avais vu autour des cœurs CPU dédiés et des ressources garanties. Je ne peux pas voir la configuration exacte de l’hôte, donc je ne peux pas dire si le mécanisme immédiat était un CPU overcommitment, des quotas, une pondération du scheduler, du throttling ou une combinaison. Je ne peux pas non plus prouver une intention. Ce n’est pas nécessaire : Linux a mesuré durablement 92–94 % de steal, et REGXA elle-même a attribué cette valeur élevée à la contention de son infrastructure partagée.
Obtenir le remboursement a demandé une nouvelle série d’insistances
Une fois le problème d’infrastructure établi, je ne voulais pas continuer à déplacer le VPS et tester d’autres nœuds. Je voulais annuler le service et récupérer mon argent.
Au départ, on ne m’a proposé qu’un montant partiel, avec un remboursement sous forme de crédit sur mon compte REGXA au lieu d’un retour sur la carte utilisée pour le paiement. Pour moi, un crédit chez le fournisseur n’équivaut pas à un remboursement lorsque je souhaite quitter le service.
J’ai donc continué à répondre et demandé que 100 % du paiement soit reversé sur le moyen de paiement d’origine. REGXA a finalement accepté et remboursé la totalité sur le moyen de paiement initial, en présentant ce remboursement intégral comme une exception.
J’apprécie qu’ils aient finalement tout remboursé. Mais le fait d’avoir dû continuer à insister sur la partie financière après que le support avait déjà reconnu la contention de l’infrastructure fait aussi partie de mon expérience.
La leçon que j’en ai gardée
L’erreur la plus facile aurait été de continuer à optimiser mon application. J’aurais pu modifier Nginx, augmenter les timeouts, réduire la concurrence, ajouter des retries, enquêter sur MongoDB ou réécrire du code backend. Certaines de ces actions auraient peut-être modifié des symptômes. Aucune n’aurait répondu à la question importante : pourquoi le CPU steal dépassait-il 90 % ?
Désormais, je ne m’arrête plus au fait que SSH fonctionne, que Nginx démarre et qu’un endpoint de santé renvoie 200. Sur un nouveau VPS, je regarde aussi %user, %system, %iowait, %idle, %steal, le CPU PSI, la run queue et la latence localhost.
Et quand quelque chose paraît suspect, je retire la charge puis je mesure à nouveau. Dans ce cas, cela a produit le résultat le plus clair de tout l’incident :
CPU user: 1.95%
CPU system: 0.59%
CPU steal: 94.17%
Je ne prétends pas que tous les VPS REGXA se comportent ainsi. J’ai testé un VPS et documenté ce qui lui est arrivé. Mais sur cette machine, les preuves étaient exceptionnellement nettes : mes applications consommaient à peine du CPU tandis que Linux indiquait que l’écrasante majorité du temps CPU virtuel était perdue à attendre la planification par l’hyperviseur. REGXA a ensuite attribué exactement ce comportement à la contention de ressources de son infrastructure partagée.
C’est pour cela que je le documente. Pas comme une note ni comme une recommandation, simplement comme une journée de ma vie de développeur — et comme une métrique que je n’ignorerai plus jamais sur un VPS.