Ganz ehrlich: Kaum jemand deployt und denkt dabei an sein LCP. Man merged den Branch, die Pipeline wird grün, das Feature ist live. Fertig. Dass genau dieser Deploy die Ladezeit von 2,1 auf 3,4 Sekunden geschoben hat, steht in keiner Fehlermeldung. Nichts ist “kaputt”. Es ist nur langsamer geworden.
Und das ist das Tückische an Performance-Regressionen: Sie werfen keinen Fehler. Sie schleichen sich mit einem ganz normalen, erfolgreichen Deploy ein und bleiben, bis jemand sie zufällig bemerkt. Meistens Wochen später, meistens ein Kunde.
Warum Regressionen fast immer an einem Deploy hängen
Deine Seite wird nicht über Nacht von selbst langsamer. Sie wird langsamer, weil sich etwas geändert hat: eine neue Library im Bundle, ein Bild ohne Größenangabe, ein Skript von einem Dritten, ein Font, der jetzt blockiert, eine Query, die eine Spalte mehr zieht. All das kommt mit einem Deploy.
Deshalb ist die ehrlichste Frage bei jeder Regression nicht “was ist langsam?”, sondern “seit wann?”. Und “seit wann” ist fast immer “seit welchem Deploy”. Wer den Zeitpunkt kennt, hat den Verdächtigen. Wer ihn nicht kennt, sucht im Nebel.
Warum du es im Durchschnitt nicht siehst
Jetzt kommt der Teil, der die meisten austrickst. Du schaust auf dein Performance-Dashboard, siehst die letzten 7 Tage, und die Kurve ist… unauffällig. Kein Ausschlag, kein Alarm. Also alles gut?
Nein. Zwei Dinge verstecken die Regression:
Der Durchschnitt glättet sie weg. Wenn ein Deploy die Hälfte deiner Seiten verlangsamt, die andere Hälfte aber gleich bleibt, bewegt sich der Mittelwert kaum. Deshalb schaut man in der Web-Performance nicht auf den Durchschnitt, sondern auf das 75. Perzentil, kurz p75. p75 heißt: 75 % deiner Besucher waren mindestens so schnell. Der Durchschnitt schmeichelt. p75 zeigt dir das Erlebnis derer, die es trifft.
Das lange Fenster verdünnt sie. Eine Regression, die vor zwei Tagen live ging, ertrinkt in fünf Tagen alter, guter Daten davor. Über eine Woche gemittelt ist der Sprung ein kleiner Hügel. Über die 24 Stunden davor und danach ist er eine Wand.
Beides zusammen sorgt dafür, dass ausgerechnet die Zahl, die den Schaden zeigt, die ist, auf die kaum jemand schaut: p75, in einem kurzen Fenster, rund um den Deploy.
Der Release-Marker: ein Zeitpunkt, mehr nicht
Damit man “rund um den Deploy” überhaupt sagen kann, muss das System wissen, wann der Deploy war. Genau das ist ein Release: ein benannter Zeitpunkt auf deiner Seite. Mehr steckt nicht dahinter. Eine Version (v2.4.1, ein Git-SHA, ein Datum, egal was) und ein Zeitstempel. Keine Deploy-Datenbank, kein Changelog, nur der Marker.
Am saubersten setzt du ihn automatisch, am Ende deines Deploy-Jobs, nach erfolgreichem Deploy:
- name: Tag fastmon release
if: success()
env:
FASTMON_TOKEN: ${{ secrets.FASTMON_TOKEN }}
FASTMON_SITE_ID: ${{ vars.FASTMON_SITE_ID }}
run: |
curl -fsS https://api.fastmon.eu/v1/sites/$FASTMON_SITE_ID/releases \
-H "Authorization: Bearer $FASTMON_TOKEN" \
-H "Content-Type: application/json" \
-d "{ \"version\": \"${{ github.sha }}\" }"
Vier Zeilen, einmal eingerichtet. Ab dann trägt jeder erfolgreiche Deploy seinen eigenen Marker, ganz ohne dass sich jemand merken muss, wann was live ging.
Was du danach vergleichst
Mit dem Marker wird aus “ist das schlechter geworden?” eine einzige Abfrage. Du wählst im Release-Picker den Deploy aus, und das Chart legt Vorher und Nachher übereinander. Programmatisch heißt der Hebel compare_to_release_id.
Und jetzt der wichtige Teil, den man einmal verstanden haben muss: Das “Vorher”-Fenster ist genau so lang wie dein “Nachher”-Fenster und endet exakt zum Zeitpunkt des Releases. Fragst du die 24 Stunden nach dem Deploy ab, vergleicht das System sie mit den 24 Stunden direkt davor. Gleiche Länge, gleiche Tageszeit, gleicher Wochentag-Mix. Nur der Deploy liegt dazwischen.
Daraus folgt ein einfacher Rat: Halt das Fenster kurz. Eine 7-Tage-Abfrage vergleicht gegen die 7 Tage davor und verwischt den Sprung wieder. Willst du eine Regression scharf sehen, nimm 1 bis 24 Stunden.
Die drei Stolperfallen
Drei Dinge lassen den Vergleich in der Praxis haken, und keins davon ist kompliziert:
- Der Zeitstempel muss stimmen. Lässt du
released_atweg, setzt der Server “jetzt”. Meistens passt das. Aber wenn dein Deploy-Job Minuten vor dem echten Live-Gehen läuft, etwa bei einem Blue/Green-Flip, dann datier den Marker auf den Moment, in dem die neue Version wirklich Traffic bekommt. Sonst schneidest du am falschen Punkt. - Releases hängen an einer Seite. Wer in einem Monorepo drei Sites ausliefert, braucht drei Release-Calls, auch wenn der Version-String identisch ist.
- Ein Rollback ist auch ein Release. Tagg ihn genauso, gerne als
rollback-v2.4.0. Dann siehst du im Chart alle drei Übergänge: den kaputten Release live, die Regression und den Rollback, der die Kurve wieder einfängt. Ehrlicher lässt sich ein schlechter Tag nicht dokumentieren.
Hinweis: Den kompletten Ablauf, von API-Token über den Release-Call aus GitHub Actions, GitLab CI oder Vercel bis zur Vergleichs-Query, findest du in unserer Doku zu Releases vergleichen. Das ist genau die Seite, die deine Entwickler brauchen.
Zwei Netze statt einem
Am besten fängst du eine Regression, bevor sie überhaupt live geht. Genau dafür laufen synthetische Tests: ein Labortest unter immer gleichen Bedingungen, der einen Sprung meldet, bevor der Deploy echte Besucher erreicht. Mehr zu Synthetic Monitoring.
Aber das Labor kennt nicht jedes Gerät und jedes Netz. Was durchrutscht, fängst du im Feld: an echten Besuchern, am p75, im kurzen Fenster rund um den Release-Marker. Mehr zu Real User Monitoring. Zwei Netze, hintereinander. Das eine vor dem Deploy, das andere danach.
Was du mitnimmst
Regressionen werfen keinen Fehler, sie hängen an einem Deploy, und der Durchschnitt über eine Woche versteckt sie zuverlässig. Sichtbar werden sie erst, wenn drei Dinge zusammenkommen: ein Marker auf dem Deploy, der p75 statt des Durchschnitts und ein kurzes Fenster rund um den Marker.
Der Marker kostet dich vier Zeilen in der CI. Den Rest macht die Abfrage. Und die nächste Regression bekommt dann keinen Wochen-Vorsprung mehr.