„Wir haben das Modul aufgeräumt, jetzt ist es viel schneller." Diesen Satz höre ich regelmäßig, und in den meisten Fällen ist er nicht belegt. Er ist auch nicht falsch. Er ist einfach nicht überprüfbar, weil niemand vorher gemessen hat, wie es war.
Das ist mehr als eine Formsache. Ohne Ausgangsmessung passieren zwei Dinge, die eine Modernisierung teuer machen. Verbesserungen lassen sich nicht belegen, also lässt sich die nächste Runde nicht begründen. Und Verschlechterungen fallen nicht auf, weil die Anwendung ja weiterläuft, nur eben etwas zäher als vorher.
Dieser Artikel beschreibt, welche drei Kennzahlen vor dem ersten Umbau stehen müssen, wie Sie sie in einem Altsystem ohne Spezialwerkzeug bekommen, und welche Messungen sich in diesem Zusammenhang nicht lohnen.
Warum ohne Messwerte nicht angefangen wird
Ein Umbau am laufenden System ist eine Wette: Es soll danach besser sein als vorher. Ohne Ausgangswert ist diese Wette nicht auflösbar, und das hat drei praktische Folgen.
Der Erfolg bleibt Behauptung. Bei der nächsten Budgetfrage steht Aufwand gegen Gefühl. Das ist genau der Vergleich, den eine technische Vorlage verliert.
Die Verschlechterung bleibt unentdeckt. Ein Umbau, der die Antwortzeit von 180 auf 260 Millisekunden hebt, erzeugt keinen Fehler und keine Meldung. Er erzeugt Beschwerden, drei Wochen später, die niemand mehr mit dem Umbau verbindet.
Die Reihenfolge bleibt Geschmackssache. Ohne Zahlen wird dort aufgeräumt, wo der Code am meisten stört. Mit Zahlen wird dort aufgeräumt, wo es am meisten bringt, und das sind selten dieselben Stellen.
Die gute Nachricht: Es braucht keine Messplattform. Für die drei Kennzahlen unten reicht, was ein Altsystem ohnehin schon produziert.
Die drei Kennzahlen, und warum nicht mehr
Drei Zahlen tragen die Entscheidung. Jede weitere kostet Zeit beim Einrichten und beim Lesen, ohne den Blick zu schärfen.
Erstens: die Antwortzeit an der Außenkante, als Perzentil. Nicht in einer einzelnen Funktion, sondern dort, wo der Nutzer wartet: beim Webserver. Und nicht als Durchschnitt, dazu unten mehr.
Zweitens: die Fehlerrate, getrennt nach erwartet und unerwartet. Ein 404 auf eine alte URL ist kein Vorfall. Ein 500 ist einer. Werden beide zusammen gezählt, verschwindet das Signal im Rauschen, und genau das ist der Zustand in den meisten Altsystemen.
Drittens: die Sättigung der einen Ressource, die zuerst ausgeht. In PHP-Anwendungen ist das fast immer eines von dreien: freie Arbeiterprozesse, Datenbankverbindungen oder Ein-/Ausgabe auf der Platte. Welche es ist, weiß das Team meist, und wenn nicht, ist die Frage selbst schon ein Befund.
Was bewusst nicht dabei ist: Auslastung der Prozessoren und des Arbeitsspeichers. Beide sind nützlich für die Fehlersuche und schlechte Kennzahlen für den Zustand, weil sie hoch sein können, ohne dass etwas fehlt, und niedrig, während alles wartet.
Wie Sie an die Zahlen kommen, ohne etwas einzubauen
Der erste Ort ist nicht die Anwendung, sondern der Webserver. Er protokolliert seit Jahren mit, meist nur ohne die Zeit.
# nginx: Antwortzeiten mitschreiben, eine Zeile Konfiguration
log_format zeiten '$remote_addr $request_method $uri '
'status=$status dauer=$request_time '
'upstream=$upstream_response_time';
access_log /var/log/nginx/access.log zeiten;Die Unterscheidung zwischen request_time und upstream_response_time ist die nützlichste Einzelinformation dieser Zeile: Die erste enthält die Zeit, die der Nutzer wartet, die zweite nur die Zeit, die die Anwendung braucht. Wo beide weit auseinanderliegen, liegt das Problem im Netz oder bei langsamen Clients, und jede Optimierung im Code geht ins Leere.
Für die Auswertung reicht die Kommandozeile. Dieser Aufruf liefert die drei Perzentile je Pfad und ist alles, was für die erste Woche gebraucht wird:
awk '{
split($0, f, "dauer="); split(f[2], g, " ");
n[$3]++; d[$3] = d[$3] " " g[1];
} END { for (p in n) print n[p], p }' /var/log/nginx/access.log \
| sort -rn | head -20Für die Datenbank gilt dasselbe: Das Protokoll langsamer Abfragen ist in jeder MySQL-Installation vorhanden und in den meisten ausgeschaltet. Eingeschaltet mit einer Schwelle von einer halben Sekunde kostet es fast nichts und liefert innerhalb eines Tages die Liste der Abfragen, die tatsächlich Zeit verbrauchen.
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 0.5;
SET GLOBAL log_queries_not_using_indexes = 'ON';
-- Danach: mysqldumpslow -s t /var/log/mysql/slow.log | head -20Die dritte Zahl, die Sättigung, steht ebenfalls schon irgendwo: Der Statusendpunkt von PHP-FPM nennt wartende Anfragen und belegte Arbeiterprozesse, und genau diese beiden Werte sind die Kennzahl.
Der Durchschnitt ist die falsche Zahl
Die häufigste Messung in Altsystemen ist die durchschnittliche Antwortzeit, und sie ist die einzige, die ich für schädlich halte, weil sie ein beruhigendes Ergebnis liefert.
Ein Beispiel mit erfundenen, aber typischen Zahlen: Neunzig Prozent der Anfragen sind eine Bildabfrage und dauern 20 Millisekunden. Zehn Prozent sind die Suche und dauern 2 Sekunden. Der Durchschnitt liegt bei 218 Millisekunden und sieht ordentlich aus. Jeder zehnte Nutzer wartet zwei Sekunden.
Deshalb wird in Perzentilen gemessen. Das 50. Perzentil ist der typische Fall, das 95. der schlechte, das 99. der, der sich als Beschwerde meldet. Wenn Sie nur eine Zahl aufschreiben können, nehmen Sie das 95. Perzentil.
Genauso wichtig: getrennt nach Pfad. Eine Gesamtzahl über alle Anfragen verrät nicht, dass die Startseite schnell und der Bestellvorgang langsam ist. Fünf bis zehn Pfade reichen, ausgewählt nach Häufigkeit und nach Wichtigkeit für das Geschäft.
Die Ausgangsmessung dauert eine Woche
Eine Stunde Messung ist keine Ausgangsmessung, sondern eine Stichprobe. Systeme haben Rhythmen: Der Montagvormittag sieht anders aus als der Freitagabend, der Monatsletzte anders als der Rest, und in vielen Häusern läuft nachts ein Lauf, der alles andere verdrängt.
Eine Woche ist das Minimum, das diese Rhythmen einmal vollständig enthält. Aufgeschrieben wird das Ergebnis an einem Ort, der in sechs Monaten noch auffindbar ist, mit Datum und mit der Angabe, welcher Stand gemessen wurde.
Ausgangsmessung 2026-10-06, Stand a3f91c, Woche 05.-11.10.
Pfad Anfragen/Tag p50 p95 p99
GET /produkt/{id} 412.000 41ms 180ms 850ms
POST /warenkorb/hinzufuegen 38.000 95ms 410ms 1.900ms
GET /suche 21.000 310ms 2.100ms 4.800ms
POST /bestellung 4.100 520ms 1.400ms 3.100ms
Fehler: 5xx 0,08 % 4xx 2,1 % (davon 90 % alte Bild-URLs)
Saettigung: PHP-FPM Arbeiter max. 42 von 50, taeglich 11:00-13:00Diese halbe Seite ist die Grundlage für jede spätere Aussage. Sie kostet eine Stunde Arbeit und eine Woche Wartezeit, und sie ist der Grund, warum die nächste Budgetfrage anders verläuft.
Wenn aus den drei Kennzahlen eine dauerhafte Sicht werden soll, die auch über Dienstgrenzen trägt, führt der Weg über OpenTelemetry in PHP und Go einführen.
Eine Messung, eine Änderung
Mit der Ausgangsmessung gilt eine Regel, die einfach klingt und in der Praxis schwer durchzuhalten ist: Zwischen zwei Messungen liegt genau eine Änderung.
Wer eine Woche lang aufräumt, einen Index setzt, einen Zwischenspeicher einbaut und danach misst, weiß am Ende, dass es besser geworden ist, aber nicht wodurch. Beim nächsten Mal wird dann alles drei gemacht, weil niemand weiß, welches davon gewirkt hat. Genau so entstehen Zwischenspeicher, die nichts bringen und trotzdem gepflegt werden.
Praktisch heißt das nicht, dass jeder Commit einzeln ausgerollt werden muss. Es heißt, dass Änderungen, die auf die Kennzahlen zielen, einzeln ausgerollt werden, und dass zwischen ihnen genug Zeit liegt, um den Unterschied zu sehen. Bei einem wöchentlichen Rhythmus sind das oft schlicht zwei Tage.
Und es heißt, Verschlechterungen zu akzeptieren, wenn sie auftreten. Eine Änderung, die das 95. Perzentil um dreißig Prozent hebt, wird zurückgedreht, auch wenn der Code danach schöner ist.
Zahlen sagen, dass etwas langsamer wurde, nicht, dass es falsch wurde. Dafür braucht es Legacy-Code testen, wenn es keine Tests gibt.
Was Sie in diesem Zusammenhang nicht messen
Zum Schluss drei Messungen, die in Modernisierungsvorhaben regelmäßig aufgesetzt werden und die Entscheidung nicht verbessern.
Codemetriken. Zyklomatische Komplexität, Kopplungsgrad, Zeilen je Klasse. Sie beschreiben den Code und nicht das Erlebnis. Ein Modul mit schlechten Werten, das seit vier Jahren niemand anfasst, kostet nichts. Die bessere Näherung für „wo tut es weh" steht in der Versionsgeschichte: die Dateien, die am häufigsten geändert werden.
Testabdeckung als Fortschrittsbalken. Nützlich als Werkzeug, schädlich als Ziel. Wer die Zahl steuert, bekommt Tests für triviale Zugriffsmethoden, weil die billig sind.
Alles, was niemand liest. Ein Diagramm, das in sechs Monaten niemand geöffnet hat, kostet Pflege und liefert nichts. Die drei Kennzahlen oben gehören an einen Ort, an den das Team ohnehin schaut, und der Rest wird eingerichtet, wenn eine konkrete Frage danach verlangt.
Wenn aus der Ausgangsmessung ein dauerhafter Blick auf das System werden soll, ist das der Punkt, an dem sich eine richtige Einführung lohnt: wie ich Observability in einem Bestandssystem einführe, steht auf einer eigenen Seite. Für den ersten Umbau reicht das Webserver-Protokoll.
Dieser Artikel gehört zu einer Reihe über Systeme, die es schon gibt. Der Rückblick ordnet alle Artikel der Reihe nach Anlass.

