Lektionen aus der Produktion.
Feldnotizen aus echten Systemen — Debugging-Geschichten, Architektur-Abwägungen, Anti-Pattern, die wir in Ausfällen bezahlt haben. Keine Tutorials, keine Hot Takes. Nur das, was um 3 Uhr morgens gehalten hat.
Symptom ≠ Ursache: Warum der Auto-Healer zum eigentlichen Problem wurde
Ein PostgreSQL-Primary auf 91 % CPU. Der Auto-Healer kickt den lautesten Query. Eine Stunde später: wieder 91 %. Die Lektion: Quickfixes können sich in Dauerschleifen verbeißen, wenn niemand fragt, welches Pattern sich wiederholt.
Cache ohne Lock ist Thundering Herd: 14 Endpoints, 8 Worker, ein Datenbank-Tod
Cache-Expire ist der einzige Moment, in dem parallele Worker synchron teuer werden. Wer keinen Lock pro Key hat, schickt bei jedem Ablauf die ganze Load auf den langsamsten Pfad.
Expression-Index ignoriert: Warum COALESCE im Index nicht zum ORDER BY passte — 29 500× Speedup
Ein funktionaler Index auf COALESCE(column, 0) hatte keinerlei Effekt. Der Planner hat ihn nicht genutzt, weil das ORDER BY eine minimal andere Expression nutzte. Lektion: Expression-Identität ist keine Empfehlung, sondern Voraussetzung.
UPDATE mit Subquery und LIMIT: Wenn der Daemon im Leerlauf dreht
Ein einfaches UPDATE-Pattern, das bei kleinen Datenmengen richtig wirkt und im Produktiv-Betrieb still stagniert. Die Ursache: Filter an der falschen Stelle zerstört den Fortschritt.
Commit vor async I/O: Wie ein Enricher den ganzen PgBouncer-Pool idle hielt
Eine Transaktion, die auf eine HTTP-Antwort wartet, ist im Connection-Pool unsichtbar — aber sie hält den Slot. Mit zwölf parallelen Daemons reicht das, um ein komplettes Backend auf 502 zu schicken.
Batch-Finalisierung auf Container-Ebene: Warum der Monitor 83 Minuten lang nichts sah
Eine Pipeline mit N parallelen Sub-Jobs finalisiert ihren Status auf Batch-Ebene — alle Worker laufen, aber der Monitor meldet Stillstand, bis der letzte Container fertig ist. Der Fix: Finalisierung pro Container, nicht pro Batch.