Was der grüne Haken tatsächlich beweist
Ein HTTP-Check beweist genau eine Sache: Unter der geprüften Adresse hat jemand mit einem Statuscode geantwortet. Wer diese Antwort geschickt hat, steht im Statuscode nicht drin. Liegt ein CDN davor, endet die Prüfung in der Regel an der nächstgelegenen Kante, und die Kante hat zwei Möglichkeiten – den Ursprung fragen oder aus dem eigenen Vorrat antworten. Der zweite Weg ist der schnellere und darum der übliche. Ein 200 sagt deshalb nichts darüber, ob die Anwendung dahinter noch läuft, ob die Datenbank erreichbar ist oder ob der Bestellprozess durchgeht.
Das ist keine Fehlfunktion des Caches, sondern seine Aufgabe. RFC 9111 beschreibt eine veraltete Antwort als eine, die zwar Ablaufinformationen trägt oder heuristisch berechnet werden darf, nach der Frischerechnung aber nicht mehr frisch ist. Erzeugen darf ein Cache sie trotzdem, aber nur unter einer von zwei Bedingungen: Er ist vom Ursprung getrennt, oder Client beziehungsweise Ursprungsserver haben es ausdrücklich erlaubt, etwa über die Erweiterungen aus RFC 5861. Untersagt eine Anweisung wie no-cache, must-revalidate, s-maxage oder proxy-revalidate die veraltete Antwort, bleibt sie auch in diesen Lagen verboten (RFC 9111). Die Kante tut also das, was ihr aufgetragen wurde – sie hält den Besucher von einem Fehlerbild fern. Nur hält sie damit gleichzeitig die Überwachung von der Lage fern.
- Was der Check belegt: Die Adresse ist erreichbar, TLS steht, ein Statuscode kam zurück, die Antwortzeit lag im Rahmen.
- Was der Check offenlässt: ob der Ursprungsserver an dieser Antwort beteiligt war und wie alt der ausgelieferte Inhalt ist.
- Was daraus folgt: Ein Ausfall des Ursprungs bleibt so lange unsichtbar, wie der Vorrat der Kante reicht – bei ungünstiger Einstellung über Stunden.
- Was das für die Erkennungszeit heißt: Das gewählte Prüfintervall verkürzt hier gar nichts, weil jede einzelne Prüfung dieselbe zwischengespeicherte Antwort erhält.
Age: der Kopf, der die Herkunft verrät
Es gibt ein Signal, das ohne Zusatzaufwand verfügbar ist und die Frage zur Hälfte beantwortet: den Age-Kopf. RFC 9111 formuliert seine Aussagekraft in zwei Sätzen, die getrennt gelesen werden müssen. Der erste: Ist ein Age-Feld vorhanden, wurde die Antwort für diese Anfrage nicht vom Ursprungsserver erzeugt oder bestätigt (RFC 9111). Der zweite schränkt die Umkehrung ein: Fehlt das Feld, folgt daraus nicht, dass der Ursprung kontaktiert wurde (RFC 9111). Ein Age-Wert ist damit ein belastbarer Nachweis für eine Cache-Antwort, sein Fehlen aber kein Nachweis für das Gegenteil.
Praktisch heißt das: Ein Age-Wert, der über mehrere Prüfungen hinweg gleichmäßig mitwächst, während sich sonst nichts ändert, ist die Signatur einer eingefrorenen Kopie. Solange der Ursprung antwortet, fällt der Wert nach jeder Auffrischung auf einen kleinen Betrag zurück. Wächst er dagegen stetig über die Frischedauer hinaus, liefert die Kante aus dem Vorrat – und das ist der Punkt, an dem eine Überwachung, die nur die Statuszeile liest, aufhört, etwas zu wissen. Der Wert allein ist noch kein Alarm, aber er ist die einzige Zahl im Standardsatz der Antwortköpfe, die überhaupt in diese Richtung zeigt.
Der Age-Kopf trägt seine Aussage nur in eine Richtung: Er beweist eine Cache-Antwort, sein Fehlen beweist keine Ursprungsantwort (RFC 9111). Wer eine Prüfregel darauf baut, formuliert sie deshalb als Nachweis und nicht als Ausschluss. Dasselbe Muster gilt für zwischengeschaltete Proxys bei der Auswertung der echten Besucher-IP: Ein gesetzter Kopf ist eine Information, ein fehlender Kopf ist keine.
Wie lang das blinde Fenster ist
Die Dauer der Blindheit lässt sich ausrechnen, sobald zwei Werte bekannt sind: die Frischedauer und die Nachfrist für Fehlerfälle. RFC 5861 führt dafür stale-if-error ein und fasst den Fehlerbegriff eng – gemeint ist jede Lage, die zu einem Statuscode 500, 502, 503 oder 504 führen würde (RFC 5861, Informational). Das Beispiel im Dokument ist so klar, dass es sich direkt übernehmen lässt: Eine Antwort mit max-age=600 und stale-if-error=1200 ist 600 Sekunden frisch und darf danach weitere 1200 Sekunden im Fehlerfall verwendet werden. Überschreitet das Alter 1800 Sekunden, muss der Cache die Fehlermeldung durchreichen (RFC 5861, Informational).
| Einstellung | Wirkung auf den Blindflug | Dokumentierte Vorgabe | Quelle |
|---|---|---|---|
| max-age | Dauer, in der die Kopie als frisch gilt | keine, stammt aus der Antwort | RFC 9111 |
| stale-if-error | Nachfrist, in der bei 5xx die alte Kopie weiterläuft | keine, stammt aus der Antwort | RFC 5861 (Informational) |
| stale-while-revalidate | alte Kopie sofort, Auffrischung im Hintergrund | keine, stammt aus der Antwort | RFC 5861 (Informational) |
| Heuristische Frische | Frischedauer ohne jede Angabe geschätzt | typischerweise 10 Prozent seit der letzten Änderung | RFC 9111 |
| CacheMaxExpire | Obergrenze, bis zu der ohne Rückfrage geliefert wird | 86.400 Sekunden, also ein Tag | Apache-Projekt |
| CacheDefaultExpire | Frist ohne Ablauf- und Änderungsdatum | 3.600 Sekunden, also eine Stunde | Apache-Projekt |
| CacheLastModifiedFactor | Faktor für die geschätzte Frische | 0,1 | Apache-Projekt |
| CacheStaleOnError | alte Kopie anstelle einer 5xx-Antwort | eingeschaltet | Apache-Projekt |
| proxy_cache_use_stale | alte Kopie bei Fehler oder Zeitüberlauf | ausgeschaltet | nginx |
| proxy_cache_background_update | Auffrischung im Hintergrund bei alter Kopie | ausgeschaltet | nginx |
Zwei Zeilen dieser Tabelle verdienen besondere Aufmerksamkeit. Erstens die Heuristik: Trägt eine Antwort weder Ablaufdatum noch Cache-Control, darf ein Cache die Frischedauer schätzen, und RFC 9111 nennt als typische Einstellung zehn Prozent der Zeit seit der letzten Änderung (RFC 9111). Bei einer Datei, deren letzte Änderung ein Jahr zurückliegt, sind das gut fünf Wochen. Zweitens die Vorgaben: In mod_cache ist das Ausliefern alter Inhalte anstelle von 5xx-Antworten voreingestellt (Apache-Projekt), in nginx steht proxy_cache_use_stale ab Werk auf off (nginx). Dieselbe Anwendung verhält sich hinter zwei Zwischenschichten also grundverschieden – und beide Verhaltensweisen sind dokumentiert, keine davon ist ein Fehler.
Solange die Kante liefern kann, verschiebt sie den sichtbaren Ausfall nach hinten. Bei max-age 600 und stale-if-error 1200 sind das 1800 Sekunden, in denen ein toter Ursprung wie ein gesunder aussieht (RFC 5861, Informational). Wer diese Spanne kennt, kann sie überwachen; wer sie nicht kennt, misst am Ende die Ausdauer des Caches und nennt das Verfügbarkeit. Wie sich dieselbe Verzögerung nach einer Auslieferung zeigt, steht in Cache-Fallen nach dem Deploy.
Cache-Status: die Antwort auf die eigentliche Frage
Seit RFC 9211 gibt es einen standardisierten Kopf, der genau das mitteilt, was eine Überwachung wissen möchte. Das Feld Cache-Status trägt eine Liste, in der jedes Mitglied für einen Cache steht, der die Anfrage bearbeitet hat; das erste Mitglied steht dem Ursprungsserver am nächsten, das letzte dem Nutzer (RFC 9211). Damit lässt sich ablesen, wie viele Schichten beteiligt waren und was jede von ihnen getan hat. Für den Fall, um den es hier geht, ist ein Satz aus dem Dokument entscheidend: Eine veraltete Antwort, die ohne Weiterleitung an den Ursprung verwendet wird – etwa weil der Ursprungsserver nicht verfügbar ist –, darf als Treffer gelten (RFC 9211).
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=600, stale-if-error=1200
Age: 1490
Cache-Status: vorschaltcache; fwd=stale; fwd-status=503, kante; hit; ttl=-890Drei Angaben in dieser Antwort widersprechen dem grünen Haken. Age steht bei 1490 Sekunden und damit weit jenseits der 600 Sekunden Frischedauer. Der Parameter ttl gibt die verbleibende Frische an und darf negativ werden, um Veralterung anzuzeigen (RFC 9211) – hier fehlen 890 Sekunden. Und fwd=stale sagt aus, dass der Cache zwar eine Antwort auswählen konnte, diese aber veraltet war (RFC 9211), während fwd-status den Statuscode trägt, den der Server der nächsten Stufe geliefert hat (RFC 9211). Der Ursprung hat also 503 geantwortet, der Besucher hat 200 bekommen. Beides steht in derselben Antwort, und eine Prüfung, die nur die Statuszeile liest, sieht davon nichts.
Wie verbreitet die Lage ist
Die Mechanik ist kein Sonderfall einzelner Aufbauten. Im Web Almanac 2025 werden 35 Prozent der mobilen HTML-Anfragen über ein CDN beantwortet, bei Ressourcen von Subdomains sind es 52 Prozent und bei Drittanbieterinhalten 71 Prozent (Web Almanac 2025). Für HTML ist der Anteil zwischen 2024 und 2025 von 33 auf 35 Prozent gestiegen (Web Almanac 2025) – der Anteil der Seiten, bei denen zwischen Prüfung und Anwendung eine Schicht liegt, nimmt also eher zu. Wer den Einsatz eines CDN plant, plant damit auch diese Schicht in die eigene Überwachung hinein.
Bei 62,2 Prozent der Desktop-Anfragen trägt die Antwort eine max-age-Angabe (Web Almanac 2021). Die Frischedauer ist damit in der Mehrheit der Fälle gesetzt und die Blindspanne grundsätzlich berechenbar.
Die Nachfrist für Fehlerfälle ist selten ausdrücklich gesetzt: bei 0,2 Prozent der Desktop-Anfragen trägt die Antwort stale-if-error (Web Almanac 2021). Wo sie fehlt, entscheidet allein die Voreinstellung der Zwischenschicht.
Mit 2,3 Prozent der Desktop-Anfragen bleibt auch die Auffrischung im Hintergrund eine Ausnahme (Web Almanac 2021), obwohl sie genau die Lücke zwischen schneller Antwort und aktuellem Stand schließt.
Bei 74,8 Prozent der Desktop-Anfragen trägt die Antwort Cache-Control, bei 24,6 Prozent weder Cache-Control noch Expires (Web Almanac 2021). In diesem Viertel entscheidet die Heuristik über die Frischedauer.
Die Verteilung erklärt, warum das Problem so oft unbemerkt bleibt. Ausdrückliche Anweisungen für den Fehlerfall sind die Ausnahme, die Voreinstellungen der Zwischenschichten dagegen die Regel – und die unterscheiden sich, wie die Tabelle zeigt, bereits zwischen zwei verbreiteten Servern. Für die Überwachung folgt daraus eine unbequeme Konsequenz: Die Blindspanne einer Website lässt sich nicht aus der Anwendung ableiten, sondern nur an der ausgelieferten Antwort messen.
Zwei Prüfpfade statt einem
Die Auflösung ist unspektakulär und kostet wenig: beide Enden der Kette getrennt prüfen und die Ergebnisse vergleichen. Der öffentliche Pfad misst, was der Besucher bekommt. Der zweite Pfad geht am Cache vorbei und misst, ob die Anwendung antwortet. Zusammen ergeben beide Ergebnisse eine Aussage, die keines von beiden allein tragen kann.
- Öffentlicher Pfad: die reguläre Adresse über die Kante, mit Zusicherungen auf Statuscode, Inhalt und Antwortzeit.
- Ursprungspfad: dieselbe Anwendung direkt angesprochen, entweder über einen eigenen Hostnamen oder über eine Anfrage mit gesetztem Host-Kopf gegen die Adresse des Ursprungs.
- Gesundheitsendpunkt: eine schlanke Adresse, die Datenbank und wichtigste Abhängigkeiten anfasst und ausdrücklich als nicht speicherbar ausgeliefert wird.
- Vergleich: Weicht der Ursprungspfad vom öffentlichen Pfad ab, ist das der Befund – und zwar bevor der Vorrat der Kante aufgebraucht ist.
Der erste Aufruf beantwortet die Herkunftsfrage, ohne dass etwas installiert werden muss. Der zweite umgeht die Kante über eine feste Namensauflösung und trifft den Ursprung direkt – hier kommt der 503 zum Vorschein, den der Besucher gar nicht zu sehen bekommt. Der dritte prüft, ob der Gesundheitsendpunkt selbst speicherbar ist; ist er es, misst auch dieser Pfad irgendwann nur noch eine Kopie seiner selbst. Wer mehrere Standorte prüft, erkennt zusätzlich, ob nur einzelne Kanten betroffen sind – dazu passt der Beitrag zum Monitoring von mehreren Standorten.
Zusicherungen, die den Unterschied messen
Aus zwei Pfaden wird erst dann eine Überwachung, wenn Regeln daran hängen. Sinnvoll sind Zusicherungen, die nicht den Statuscode wiederholen, sondern Herkunft und Alter der Antwort bewerten. Drei Regeln decken den Großteil der Fälle ab: ein Höchstwert für Age auf dem öffentlichen Pfad, ein Ausschluss von fwd=stale über mehrere aufeinanderfolgende Prüfungen und ein harter Statusvergleich zwischen öffentlichem Pfad und Ursprungspfad.
from dataclasses import dataclass
FEHLER_STATUS = {500, 502, 503, 504} # Fehlerbegriff aus RFC 5861
@dataclass
class Antwort:
status: int
age: int | None # None heißt: Kopf war nicht gesetzt
max_age: int | None
stale_if_error: int | None
fwd: str | None # Wert aus Cache-Status, falls vorhanden
def blindfenster(a: Antwort):
"""Sekunden, in denen ein toter Ursprung verdeckt bleiben kann."""
if a.max_age is None:
return None # ungemessen, nicht 0
return a.max_age + (a.stale_if_error or 0)
def lage(a: Antwort) -> str:
if a.status in FEHLER_STATUS:
return "fehler wird durchgereicht"
if a.fwd == "stale":
return "ursprung antwortet nicht"
if a.age is None:
return "unbestimmt" # kein Nachweis in beide Richtungen
if a.max_age is not None and a.age > a.max_age:
return "veraltete kopie"
return "frisch"
def restspanne(a: Antwort):
fenster = blindfenster(a)
if fenster is None or a.age is None:
return None
return max(fenster - a.age, 0)Die Funktionen geben bewusst None zurück, wenn der Age-Kopf fehlt oder max-age nicht gesetzt ist. Ein fehlender Kopf ist kein Nullwert, sondern eine nicht durchgeführte Messung – und eine Überwachung, die beides gleich behandelt, meldet Ruhe, wo sie nichts gemessen hat. Dieselbe Trennung lohnt sich bei Antwortzeiten, wo ein einzelner Ausreißer im Mittelwert verschwindet und erst in den Perzentilen p95 und p99 sichtbar wird.
Alarmieren, bevor der Vorrat aufgebraucht ist
Der Zeitpunkt des Alarms entscheidet, ob die Überwachung noch nützt. Fällt der Alarm erst, wenn die Kante keine Kopie mehr hat, ist der Ausfall bereits für alle sichtbar – dann meldet die Überwachung dasselbe wie das Telefon. Der Gewinn liegt in der Spanne davor: Sie beginnt in dem Moment, in dem der Ursprungspfad kippt, und endet, sobald das Alter der ausgelieferten Antwort die Summe aus Frischedauer und Nachfrist überschreitet (RFC 5861, Informational).
- Stufe 1, sofort: Der Ursprungspfad antwortet mit 500, 502, 503 oder 504 (RFC 5861, Informational), der öffentliche Pfad noch mit 200. Das ist die stille Phase und der früheste sinnvolle Zeitpunkt für eine Meldung.
- Stufe 2, nach Bestätigung: Auf dem öffentlichen Pfad taucht fwd=stale auf oder ttl wird negativ (RFC 9211). Jetzt liefert die Kante nachweislich aus dem Vorrat.
- Stufe 3, vor dem Ende: Age nähert sich der Summe aus max-age und stale-if-error. Ab hier ist der Ausfall für Besucher absehbar und nicht mehr nur für die Überwachung.
- Dauerregel: Der Gesundheitsendpunkt bleibt unzwischengespeichert, sonst verliert Stufe 1 ihre Grundlage. Wie sich Fehlerantworten sauber von Ausreißern trennen lassen, steht im Beitrag zur Fehlerrate von 5xx-Antworten.
Ein grüner Haken ohne Aussage über die Herkunft der Antwort ist eine Aussage über den Cache, nicht über die Website. Der Unterschied kostet in der Einrichtung kaum etwas und entscheidet darüber, ob eine Meldung rechtzeitig kommt.
— XICTRAQ
Was sich diese Woche einrichten lässt
Der Aufwand bleibt überschaubar, weil alle benötigten Angaben bereits in den Antwortköpfen stehen. Ein Durchgang: An einer Beispielseite die Köpfe Age, Cache-Control und Cache-Status abrufen und die Blindspanne notieren. Danach den Ursprung als eigenen Prüfpfad anlegen, entweder über einen internen Hostnamen oder über eine feste Namensauflösung. Zuletzt eine Zusicherung auf den Age-Wert setzen und den Gesundheitsendpunkt auf no-store stellen. Ein vollständiges Inventar der geprüften Adressen zeigt dabei, welche Einstiegspunkte bisher gar keinen Prüfpfad haben.
Vor Lastspitzen lohnt sich der Durchgang doppelt, weil dann Trefferquote der Kante und Last am Ursprung gleichzeitig steigen – was dabei zu beachten ist, steht in der Vorbereitung auf das Weihnachtsgeschäft. In XICTRAQ lassen sich beide Pfade als getrennte Prüfungen führen, Kopfzusicherungen gehören zur API-Überwachung, und die Meldung geht über die eingerichteten Alarmkanäle hinaus auch in die Statusseite, damit Kundinnen und Kunden dieselbe Lage sehen wie das Team. Wer das Zusammenspiel zuerst ansehen möchte, findet es in der Demo-Ansicht; die Grundlagen der Erreichbarkeitsprüfung stehen unter Uptime-Monitoring.
Dieser Beitrag stützt sich auf: RFC 9111 (HTTP Caching, Abschnitte 4.2.2, 4.2.4 und 5.1), RFC 5861 (Informational; stale-if-error und stale-while-revalidate), RFC 9211 (Cache-Status-Kopf), die Dokumentation des Moduls mod_cache im Apache-Projekt und die Dokumentation von ngx_http_proxy_module in nginx. Die Verbreitungszahlen stammen aus dem Kapitel Caching des Web Almanac 2021 und dem Kapitel CDN des Web Almanac 2025.