Zurück zum Blog
31. August 2026Sergei Solod10 Min. Lesezeit

Mein VPS war online. Dann wartete Linux 18 Sekunden auf Festplattenlesevorgänge

Ein realer Linux-Debugging-Fall aus der Produktion: Der VPS blieb online, während fast keine Nutzarbeit mehr vorankam. Der I/O-Druck näherte sich 100 %, Reads dauerten bis zu 18,7 Sekunden, EXT4 und Nginx blockierten, während das Backend selbst noch in rund 3 ms antwortete.

LinuxDevOpsVPSPerformanceFehlersuche

Bevor es um die Diagnose geht, möchte ich eines klarstellen: Ich habe FDCServers insgesamt positiv in Erinnerung. Dieser Text ist keine Warnung vor dem Anbieter und kein Urteil über dessen gesamte Infrastruktur. Ich hatte einen einzelnen VPS, in einem bestimmten Zeitraum, mit einem ungewöhnlich schwierigen Problem.

Lange Zeit tat dieser VPS genau das, was ich brauchte, und trug normalen Produktionsverkehr. Dann änderte sich etwas. Gewöhnliche Requests wurden absurd langsam. Seiten öffneten sich erst zäh und später teilweise gar nicht mehr. Zu anderen Zeiten sah die Maschine wieder normal aus, bevor ich den Fehler sauber untersuchen konnte.

Im schlimmsten Zustand erfasste ich:

CPU iowait:       97–100%
I/O PSI full:     ~95–98%
read latency:     up to 18.7 seconds
flush latency:    up to 53.6 seconds
I/O queue depth:  128+

Nginx lief. Das Backend lief. Die VM war online. Trotzdem kam fast keine sinnvolle Arbeit mehr voran.

Der Produktionsausfall war ärgerlich, die Fehlersuche selbst aber ehrlich gesagt spannend. Genau dafür mag ich Linux: Ein System kann von außen lebendig wirken, während mehrere voneinander unabhängige Kernel-Signale zeigen, an welcher Stelle nützlicher Fortschritt stoppt. Dieser Artikel handelt von diesen Spuren, nicht davon, FDCServers als guten oder schlechten Anbieter zu bewerten.

active (running) bedeutete plötzlich erstaunlich wenig

Ich begann mit den üblichen Checks:

top
free -h
df -h
systemctl status nginx

In gesunden Phasen sah ich ungefähr:

D-state processes: 0
CPU iowait:        ~0%
disk latency:      ~2–4 ms
I/O PSI some:      0.04
I/O PSI full:      0.04

Hätte ich mich nur in so einem Moment eingeloggt, wäre der VPS völlig gesund erschienen. Wenig später konnte normaler Traffic den Zustand komplett verändern. Ein gesunder Snapshot sagt bei einem intermittierenden Fehler kaum etwas über den eigentlichen Fehlerzustand aus. Ich musste Daten sammeln, während das Problem tatsächlich auftrat.

Das iostat-Sample, das die Untersuchung verändert hat

r_await = 18744 ms
f_await = 53561 ms
aqu-sz  = 128.54
util    ≈ 100%
read    = 88 KB/s

Abgeschlossene Reads dauerten rund 18,7 Sekunden, Flushes etwa 53,6 Sekunden. Die durchschnittliche Queue lag über 128, während der nützliche Lesedurchsatz nur 88 KB/s betrug.

Das sah nicht nach Storage aus, der wegen eines anspruchsvollen Workloads effizient beschäftigt war. Der virtuelle Blockpfad war praktisch ausgelastet und erledigte trotzdem kaum Arbeit. Hohe Auslastung allein ist kein Fehler. Hohe Auslastung zusammen mit extremer Latenz, großer Queue, blockierten Tasks, minimalem Durchsatz und fehlgeschlagenen Requests ist etwas völlig anderes.

Ich hörte auf, iowait als Diagnose zu behandeln

blocked processes: 4–9
CPU iowait:        97–100%
CPU idle:          0%

Man könnte daraus verkürzt ableiten, die CPU verbringe 100 % ihrer Zeit mit dem Warten auf den Datenträger. Als Intuition ist das brauchbar, Linux-Accounting ist aber komplizierter. iowait misst den Datenträger nicht direkt. Deshalb behandelte ich die Zahl nur als Symptom und suchte nach unabhängigen Signalen.

PSI zeigte, dass I/O die Nutzarbeit praktisch stoppte

cat /proc/pressure/io

Während einer schweren Phase:

some avg10=99.14
full avg10=95.55

Bei späteren Reproduktionen näherte sich full 98 %. Bei I/O-Pressure beschreibt some Zeit, in der mindestens ein Teil der nicht-idlen Arbeit durch I/O blockiert ist. full beschreibt Zeit, in der alle nicht-idlen Tasks gleichzeitig auf I/O festhängen. Nahe 100 % bedeutet weit mehr als nur ein beschäftigtes Laufwerk: Der Workload bekommt kaum noch Gelegenheit, Fortschritt zu machen.

D-state brachte mich davon ab, einen einzelnen Prozess zu beschuldigen

ps -eo state,pid,ppid,etime,wchan:50,comm,args | awk 'NR==1 || $1 ~ /^D/'

Ein einzelner Prozess kurz in D-state beweist kein Storage-Problem. Entscheidend war, welche Prozesse gleichzeitig festhingen. Ich sah unter anderem jbd2, systemd-journald, Nginx-Worker, Nginx-Cache-Prozesse und andere Dateisystemaktivität.

Wenn nur mein Backend hängt, untersuche ich das Backend. Wenn nur Nginx hängt, untersuche ich Nginx. Wenn Nginx, Systemjournal und EXT4-Journal gleichzeitig keinen Fortschritt machen, wird ihre gemeinsame Abhängigkeit interessanter als jeder einzelne Prozess. Hier war das Dateisystem samt Storage-Pfad darunter diese Abhängigkeit.

Die Kernel-Stacks zeigten die nächste Schicht

Der EXT4-Journal-Thread erschien in Pfaden wie:

wait_on_buffer
jbd2_log_wait_commit
jbd2_journal_commit_transaction

Nginx-Worker steckten in gewöhnlichen Lesepfaden:

folio_wait_bit_common
filemap_read
generic_file_read_iter
ext4_file_read_iter
vfs_read
pread64

Einmal meldete der Kernel:

INFO: task nginx blocked for more than 122 seconds.

systemctl status nginx konnte gleichzeitig weiterhin active (running) anzeigen. Beides war korrekt: Der Prozess existierte, aber ein Nginx-Task hatte über zwei Minuten lang keine Nutzarbeit abschließen können. Ein laufender Prozess ist nicht automatisch ein gesunder Dienst.

Mein sauberster Test dauerte ungefähr drei Millisekunden

Über Nginx schlug der Request fehl:

HTTP=000
SSL connection timeout

Direkt zum lokalen Backend:

connect = 0.000423 s
TTFB    = 0.003063 s
total   = 0.003139 s

Rund 3 ms. Der konkrete HTTP-Status war für diesen Test unwichtig. Das Backend nahm die Verbindung an, verarbeitete die Anfrage und antwortete fast sofort. Zur selben Zeit waren Nginx-Worker in EXT4-Lesepfaden blockiert.

application execution       → progressing normally
filesystem-backed web path  → not progressing normally

Damit wurde eine Ursache im Anwendungscode immer schwerer zu rechtfertigen.

Der gleiche VPS konnte in etwa 30 Sekunden kippen

Vor einer Reproduktion:

HTTP:          200
D-state:       0
CPU iowait:    3%
r_await:       ~1.18 ms
I/O PSI full:  ~2.95%

Etwa eine halbe Minute später:

D-state:       4
CPU iowait:    91%
CPU idle:      0%
I/O PSI some:  86.11%
I/O PSI full:  78.02%
r_await:       236.50 ms
HTTP:          000

Später noch schlechter:

CPU iowait:    96–100%
I/O PSI full:  ~98%
HTTPS queue:   512
HTTP:          000

Nach dem Entfernen der Last konnte die Gegenbewegung schnell erfolgen:

D-state:      0
CPU iowait:   6%
r_await:      ~0.98 ms
queue depth:  ~0.07
HTTP:         200

Genau deshalb sind intermittierende Infrastrukturfehler so mühsam. Zehn Minuten später kann jemand denselben VPS untersuchen und ehrlich Sub-Millisekunden-Latenz sehen. Er betrachtet schlicht einen anderen Zustand.

Eine Latenz von null kann erstaunlich wenig aussagen

Ich sah auch ein iostat-Intervall mit r_await = 0, obwohl das System eindeutig ungesund war: hoher iowait, Prozesse in D-state, offene I/O-Operationen, kaum abgeschlossene Reads und fast kein Durchsatz.

Durchschnittswerte abgeschlossener Operationen werden wenig hilfreich, wenn im Messfenster fast nichts fertig wird. Null bedeutet dann nicht zwangsläufig, dass Reads sofort abgeschlossen wurden; es können schlicht zu wenige Abschlüsse existieren, um die hängenden Operationen abzubilden.

Seitdem bewerte ich Latenz, IOPS, Durchsatz, Queue-Tiefe, In-flight-I/O, D-state, PSI und tatsächliche Request-Abschlüsse gemeinsam.

Aus einem Incident wurde eine längere Support-Untersuchung

Der erste schwere Vorfall fiel mit einem geplanten Backup auf der ursprünglichen Infrastruktur zusammen, und FDCServers bestätigte, dass dieses Backup lief. Das war zunächst eine plausible Erklärung. Ich reproduzierte denselben Fehlertyp aber später nach Abschluss des Backups und außerhalb des ursprünglichen Backup-Fensters.

Das Problem kehrte an mehreren Tagen zurück. Bei einem Vorfall war der VPS laut meinen Service-Logs später 4 Stunden, 41 Minuten und 15 Sekunden nicht verfügbar. Ich kann nicht beweisen, dass der Storage-Stall den VM-Zustand verursachte; dafür hätte ich Host-seitige Daten benötigt.

application
    ↓
Linux VFS
    ↓
EXT4
    ↓
virtual block device
    ↓
?

Hinter dem Fragezeichen können Virtualisierung, Host-Queues, Storage-Netzwerk, verteiltes Storage, physische Datenträger, Scheduler und andere Systeme liegen, die der Gast nicht sehen kann. Ich konnte beobachten, wo der Fehler auftrat, nicht die physische Root Cause.

FDCServers eskalierte das Problem intern und migrierte den VPS schließlich auf einen anderen Node. Danach erfasste ich erneut einen schweren Storage-Stall aus Sicht des Gasts. Das beweist nicht, dass alle FDCServers-Nodes ein Storage-Problem hatten. Es beweist nur, dass mein Problem aus meiner Sicht nicht beseitigt war.

Warum ich daraus trotzdem keine negative FDCServers-Geschichte mache

Aus einem Infrastrukturincident ein Urteil über einen ganzen Anbieter zu machen, ist einfach. Genau das möchte ich vermeiden.

Für mich gibt es einen Unterschied zwischen einem Dienst, dessen normales Betriebsmodell grundsätzlich nicht zu meinem Workload passt, und einem intermittierenden Infrastrukturproblem, das schwer reproduzierbar ist und lange zur Eingrenzung braucht. Meine Erfahrung mit FDCServers fühlte sich nach dem zweiten Fall an.

Der VPS hatte vor dem Incident normal funktioniert und echten Produktionsverkehr getragen. Der Support untersuchte das Problem und versuchte es zu beheben. Irgendwann hatte ich genug Evidenz und wollte diesen konkreten VPS nicht länger für Produktion verwenden.

Ich bat um Kündigung und Rückerstattung. FDCServers erstattete mir das Geld. Das gehört für mich zur Gesamtbewertung der Erfahrung.

Ich habe die heutige Infrastruktur nicht erneut getestet und kann daher nicht sagen, wie ein FDCServers-VPS heute läuft. Ebenso habe ich keine Evidenz dafür, dass mein einzelner Vorfall repräsentativ für die gesamte Plattform war. Infrastruktur verändert sich ständig. Ich mache aus einem schwierigen Incident auf einem VPS kein dauerhaftes Urteil über den Anbieter. Ich empfehle FDCServers hier auch nicht; ich beschreibe lediglich meinen Fall.

Am meisten Spaß gemacht hat mir Linux selbst

Der Ausfall war frustrierend, die Untersuchung dagegen wirklich interessant. Ich hatte Freude daran, die Grenze des Fehlers zu finden.

Für die physische Root Cause fehlte mir die Sicht. Die entscheidende Frage war einfacher: An welcher Schicht hört Nutzarbeit auf, fertig zu werden?

Das Backend antwortete in ungefähr drei Millisekunden. Nginx war aktiv, steckte aber laut Kernel-Stacks in EXT4-Reads. vmstat zeigte blockierte Prozesse und extremen I/O wait. PSI zeigte fast vollständige I/O-Stalls. iostat zeigte enorme Latenz und Queueing. D-state zeigte mehrere voneinander unabhängige Prozesse, die gleichzeitig warteten. Der Kernel meldete sogar einen Nginx-Task, der länger als 122 Sekunden blockiert war.

Kein einzelner Messwert löste den Fall. Die Übereinstimmung der Signale tat es. Genau das ist einer der Gründe, warum ich Linux mag: Man beginnt mit etwas Vagem wie „meine Website öffnet manchmal nicht“ und kann daraus Schritt für Schritt eine präzise Aussage über die Schicht ableiten, in der Nutzarbeit keinen Fortschritt mehr macht.

Mein heutiger Debugging-Workflow

top
free -h
df -h

date -u
uptime
cat /proc/pressure/io
cat /proc/pressure/memory
cat /proc/pressure/cpu
vmstat 1 10
iostat -x 1 10
ps -eo state,pid,ppid,etime,wchan:50,comm,args | awk 'NR==1 || $1 ~ /^D/'
ss -lntp
journalctl -k --since "30 min ago" --no-pager

Wann immer möglich, teste ich außerdem jeden Teil des Request-Pfads separat:

public request
      ↓
reverse proxy
      ↓
direct backend
      ↓
filesystem
      ↓
block device

Ich frage nicht mehr nur, warum der Server langsam ist. Ich frage: An welcher Schicht hört Nutzarbeit auf, abgeschlossen zu werden? Diese Frage führt zu wesentlich besseren Experimenten.

Eine letzte Regel: Evidenz vor dem Reboot sichern

Ein Reboot kann genau das sein, was die Produktion braucht, aber er kann auch den wertvollsten Fehlerzustand löschen, den man je zu sehen bekommt.

Before reboot:
D-state:     high
I/O PSI:     ~97%
iowait:      ~100%
queues:      large
requests:    failing

After reboot:
D-state:     0
latency:     milliseconds
requests:    healthy

Wenn Verfügbarkeit und geschäftliche Auswirkungen es erlauben, erfasse ich vorher UTC-Zeit, PSI, vmstat, iostat, D-state, wchan, Kernel-Meldungen, Socket-Queues und Request-Timings. Danach stelle ich den Dienst wieder her.

Der Server lief. Der Workload nicht.

Ich habe nie erfahren, welche Host-seitige Komponente den Vorfall letztlich verursachte. Ich kann keinen bestimmten SSD-Defekt behaupten, keinen Storage-Node benennen und nicht beweisen, was hinter dem virtuellen Blockgerät passierte.

Was ich innerhalb von Linux feststellen konnte, reichte aus:

read latency:       up to 18.7 s
flush latency:      up to 53.6 s
I/O PSI full:       almost 100%
iowait:             almost 100%
I/O queue:          128+
Nginx:              blocked in filesystem reads
EXT4/jbd2:          blocked waiting for I/O
direct backend:     ~3 ms
HTTP through Nginx: timing out

Das genügte, um meine Anwendung von der fehlerhaften Schicht zu trennen und eine operative Entscheidung zu treffen. FDCServers erstattete den VPS, ich zog weiter und mache aus einem schwierigen Infrastrukturincident kein dauerhaftes Urteil über den Anbieter.

Geblieben ist eine nützlichere Erkenntnis: Ein Prozess kann laufen, ein Dienst kann active sein, eine VM kann online sein und Ping kann funktionieren, während die Maschine trotzdem fast keine Nutzarbeit mehr erledigt.

Linux liefert genug Evidenz, um diesen Unterschied zu erkennen. Man muss nur die richtigen Fragen stellen, solange der Fehler noch da ist.