Das hier soll keine negative Bewertung von REGXA sein, und ich möchte niemandem sagen, ob er dort einen VPS kaufen sollte oder nicht. Es ist einfach ein ganz normaler Tag aus meinem Entwickleralltag.
Ich verschob eine normale Workload auf einen KVM-VPS mit 2 vCPU, 2 GB RAM und 60 GB NVMe. Nginx lief, das Backend lief. Trotzdem verhielt sich die Maschine, als wäre sie massiv überlastet: Requests stauten sich, TLS wurde langsam, Verbindungen blieben offen und manche Requests endeten erst nach mehr als zwei Minuten mit HTTP 504.
Die CPU-Abrechnung änderte die Richtung der Fehlersuche
Meine erste Vermutung war naheliegend: Irgendetwas im VPS verbraucht die CPU. Dann startete ich 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%
Einzelne Messpunkte lagen wiederholt bei ungefähr 89–98 % Steal. Auch der CPU-Druck war extrem:
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
Das war eine VM mit nur zwei vCPUs. Unter Linux warteten ausführbare Prozesse auf CPU-Zeit. Entscheidend war nicht die normale CPU-Auslastung der Anwendungen, sondern %steal.
Hohe CPU-Auslastung und CPU-Steal sind zwei verschiedene Probleme
Wenn meine Anwendung den Prozessor tatsächlich ausgelastet hätte, wären hohe Werte bei user oder system zu erwarten gewesen. Stattdessen sah es ungefähr so aus:
user: 4%
system: 1%
steal: 93%
CPU-Steal bezeichnet Zeit, in der eine virtuelle CPU bereit zum Ausführen ist, vom Hypervisor aber nicht eingeplant wird. Wenn ich also sage, dass dem VPS CPU-Zeit entzogen wurde, meine ich genau diesen technischen Virtualisierungsbegriff. Ich kann nicht beweisen, dass REGXA absichtlich physische Kerne, die exklusiv mir gehört hätten, einem anderen Kunden zugewiesen hat. Aus Gastmetriken lässt sich auch keine Absicht ableiten. Belegen kann ich aber, dass der Gast wiederholt ausführbare Arbeit hatte und trotzdem keine CPU-Scheduling-Zeit bekam.
Ich entfernte den gesamten Produktionstraffic
Es blieb ein offensichtlicher Einwand: Vielleicht verursachte meine Workload das Problem selbst. Also entfernte ich diese Variable. Ich verschob die aktive Last auf einen anderen Server, leitete keinen Produktionstraffic mehr auf diesen VPS, ließ die Warteschlangen leerlaufen und wiederholte die Messung.
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%
Das Ergebnis wurde schlechter. Einzelne vmstat-Samples zeigten weiterhin 91–98 % Steal, und bis zu 15 ausführbare Prozesse warteten auf CPU-Zeit. Entscheidend war diese Kombination:
user: 1.95%
system: 0.59%
steal: 94.17%
Meine Anwendungen taten nun fast nichts mehr, trotzdem verlor die VM nahezu ihre gesamte Scheduling-Zeit. Normale Produktionslast war damit keine überzeugende Erklärung mehr.
Sogar localhost wurde absurd langsam
Ich testete zusätzlich HTTPS über 127.0.0.1. Damit verschwanden öffentliches DNS, mein ISP, geografische Entfernung und der externe Netzwerkpfad aus dem Test.
Unter Last scheiterten vier von zehn localhost-HTTPS-Versuchen bereits beim TLS-Handshake. Die erfolgreichen Requests benötigten 29,30, 22,77, 12,25, 11,87, 11,12 und 9,40 Sekunden. Einzelne TLS-Handshakes dauerten allein rund neun Sekunden.
Nach dem Entfernen des Produktionstraffics wurde localhost schneller, blieb aber instabil: 0,061, 0,745, 0,830, 0,873, 1,010, 1,117, 1,121, 2,188 und 3,355 Sekunden. Derselbe lokale Vorgang konnte einmal etwa 61 ms und beim nächsten Versuch mehr als 3,3 Sekunden dauern.
Der restliche Stack zeigte die Folgen
Zu einem Zeitpunkt sah ich ungefähr 450 etablierte Verbindungen, 122 verwaiste Verbindungen, 110 FIN-WAIT-1- und 33 CLOSE-WAIT-Verbindungen. Die Listen-Warteschlange des lokalen Backends lag bei etwa 14–15, die HTTPS-Warteschlange bei ungefähr 40.
Nginx protokollierte HTTP-504-Antworten nach 142,857, 138,902, 135,064, 129,819 und 128,657 Sekunden. Andere Requests blieben ungefähr 67–130 Sekunden offen. Außerdem gab es Secure-Connect-Timeouts nach rund 35–41 Sekunden, Datenbank-Netzwerk-Timeouts und verzögerte TLS-Vorgänge.
Das konnte wie mehrere voneinander unabhängige Nginx-, Datenbank-, Netzwerk- oder Backend-Probleme aussehen. Doch längere Timeouts erzeugen keine CPU-Zeit, die der Hypervisor nicht einplant.
RAM und Speicher erklärten das Verhalten nicht
Der VPS hatte noch ungefähr 1,0–1,1 GiB verfügbaren RAM, praktisch keinen Swap-Verbrauch, keine OOM-Ereignisse und keine Aktivität des OOM-Killers. Das Dateisystem war nur zu etwa 20 % belegt, rund 44 GB waren frei. Der I/O-Wait lag während der wichtigen CPU-Messungen unter 1 %.
Der Arbeitsspeicher war nicht erschöpft, die Platte war nicht voll und meine Anwendungen verbrauchten nicht die fehlende CPU-Zeit. Die dominierende Kennzahl blieb %steal.
Ein gesunder KVM-VPS sah völlig anders aus
Ich führte dieselbe Art von Diagnose auf einem anderen KVM-VPS aus, der gleichzeitig normalen Produktionstraffic bediente:
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
Dort lagen zehn lokale HTTPS-Requests zwischen ungefähr 37 und 69 ms. Auf einem anderen tatsächlich stark beschäftigten Produktions-VPS maß ich später 61,71 % User-CPU, 5,08 % System-CPU, 24,09 % Idle und nur 0,13 % Steal.
Genau diese Unterscheidung ist für mich heute entscheidend. Ein VPS kann ausgelastet sein, weil meine Software den Prozessor wirklich benutzt. Das ist etwas völlig anderes als ein Gast, der mehr als 90 % der gemessenen CPU-Zeit auf den Hypervisor wartet.
REGXA bestätigte schließlich Ressourcenkonkurrenz in der Infrastruktur
Aus der VM heraus konnte ich den Gast messen, aber nicht den physischen Host, dessen Scheduler-Konfiguration, CPU-Quoten oder benachbarte VMs sehen. REGXA konnte das.
Der Support erklärte mir schließlich, dass der VPS auf einer shared CPU infrastructure lief, CPU-Ressourcen zwischen mehreren VMs geteilt würden und die Performance von der Auslastung des physischen Nodes abhängen könne. Außerdem teilte man mir mit, dass die Frankfurter Infrastruktur besonders stark ausgelastet sei, und führte meinen erhöhten CPU-Steal ausdrücklich auf resource contention on the underlying infrastructure zurück.
REGXA erklärte zudem, CPU-Quoten oder Scheduling-Richtlinien auf dieser Infrastruktur nicht ändern und dem Shared-VPS keine zusätzlichen dedizierten CPU-Ressourcen zuweisen zu können. Als technische Lösung wurde ein Umzug an einen Standort mit geringerer Auslastung angeboten.
Das ließ sich für mich nur schwer mit Formulierungen vereinbaren, die ich zuvor zu dedizierten CPU-Kernen und garantierten Ressourcen gesehen hatte. Ich kenne die genaue Host-Konfiguration nicht und kann daher nicht sagen, ob unmittelbar CPU-Overcommitment, Quoten, Scheduler-Gewichtung, Throttling oder eine Kombination davon verantwortlich war. Absicht kann ich ebenfalls nicht beweisen. Das muss ich auch nicht: Linux zeigte dauerhaft 92–94 % Steal, und REGXA selbst führte den erhöhten Wert auf Konkurrenz innerhalb der Shared-Infrastruktur zurück.
Auch für die Rückerstattung brauchte es weitere Hartnäckigkeit
Nachdem das Infrastrukturproblem klar war, wollte ich den VPS nicht immer weiter verschieben und andere Nodes testen. Ich wollte kündigen und mein Geld zurück.
Zunächst wurde mir nur ein Teilbetrag angeboten, und zwar als Guthaben auf meinem REGXA-Konto statt als Rückzahlung auf die verwendete Karte. Wenn ich einen Anbieter verlassen möchte, ist internes Guthaben für mich kein gleichwertiger Ersatz für eine Rückerstattung.
Also antwortete ich weiter und verlangte, dass 100 % der Zahlung an die ursprüngliche Zahlungsmethode zurückgehen. Schließlich stimmte REGXA zu und erstattete den vollständigen Betrag auf die ursprüngliche Zahlungsmethode. Die vollständige Rückerstattung wurde als Ausnahme bezeichnet.
Ich erkenne an, dass am Ende alles zurückgezahlt wurde. Dass ich nach der bereits bestätigten Ressourcenkonkurrenz trotzdem noch für die finanzielle Lösung nachhaken musste, gehört jedoch ebenfalls zu meiner Erfahrung.
Was ich daraus mitgenommen habe
Der einfachste Fehler wäre gewesen, meine Anwendung weiter zu optimieren. Ich hätte Nginx-Einstellungen ändern, Timeouts erhöhen, die Parallelität reduzieren, Retries ergänzen, MongoDB untersuchen oder Backend-Code umschreiben können. Einzelne Symptome hätten sich dadurch vielleicht verändert. Die entscheidende Frage wäre unbeantwortet geblieben: Warum lag CPU-Steal über 90 %?
Heute höre ich bei einem neuen VPS nicht mehr auf, wenn SSH funktioniert, Nginx startet und ein Health-Endpoint HTTP 200 liefert. Ich prüfe auch %user, %system, %iowait, %idle, %steal, CPU PSI, Run Queue und localhost-Latenz.
Und wenn etwas verdächtig aussieht, entferne ich die Workload und messe erneut. In diesem Fall ergab das die klarste Messung des gesamten Vorfalls:
CPU user: 1.95%
CPU system: 0.59%
CPU steal: 94.17%
Ich behaupte nicht, dass sich jeder REGXA-VPS so verhält. Ich habe einen VPS getestet und dokumentiert, was dort passiert ist. Bei dieser VM war die Beweislage jedoch ungewöhnlich eindeutig: Meine Anwendungen verbrauchten kaum CPU, während Linux meldete, dass der überwiegende Teil der virtuellen CPU-Zeit beim Warten auf den Hypervisor verloren ging. REGXA führte genau dieses Verhalten später auf Ressourcenkonkurrenz in der Shared-Infrastruktur zurück.
Darum dokumentiere ich den Fall. Nicht als Bewertung oder Kaufempfehlung, sondern einfach als einen Tag aus meinem Entwickleralltag — und als Erinnerung an eine Kennzahl, die ich auf einem VPS nie wieder ignorieren werde.