Die Herausforderung
Ein schnell wachsendes B2B-SaaS stieß an eine Grenze. Seine Python-/FastAPI-API versorgte Dashboards für Tausende platzbasierter Konten, und der Lesepfad war zu einem Geflecht aus N+1-ORM-Abfragen, wiederholten Berechtigungsprüfungen und Feature-Flag-Abfragen pro Anfrage geworden. Die p95-Latenz der meistgenutzten Endpunkte war von 380 ms beim Launch auf 1,8 s gestiegen, die RDS-CPU lag während der Geschäftszeiten bei 80 %, und das Engineering-Team prüfte bereits ein vertikales RDS-Upgrade, das die Rechnung um rund 3.400 $/Monat erhöht hätte.
Schlimmer noch: Die Langsamkeit war für die Hälfte der Kundenbasis unsichtbar, weil sich das Dashboard progressiv aufbaut – als sich Kunden beschwerten, hatte das Team bereits eine Enterprise-Verlängerung wegen „Das Dashboard fühlt sich kaputt an“ verloren. Das Team brauchte eine Lösung in Wochen, keine sechsmonatige Re-Plattformierung.
Unsere Lösung
Wir haben eine disziplinierte, dreistufige Redis-Caching-Schicht vor die am stärksten genutzten Lesepfade gesetzt und das Datenmodell so umgestaltet, dass es sicher gecacht werden kann. Die Investition lag in Cache-Key-Design, Invalidierungsverträgen und Observability – nicht darin, dem Problem einfach mehr Speicher entgegenzuwerfen.
Stufe 1: Memoization pro Anfrage innerhalb des FastAPI-Dependency-Containers, die doppelte Abfragen innerhalb einer einzigen Anfrage eliminiert.
Stufe 2: ein gemeinsamer Redis-7-Cluster (Cluster-Modus, AWS ElastiCache) für häufige Lesezugriffe – Berechtigungssätze, Feature-Flags, Kontometadaten, Dashboard-Aggregate – mit expliziten TTLs und einem typisierten Pydantic-Envelope, sodass zwischengespeicherte Payloads versioniert und sicher weiterentwickelbar sind.
Stufe 3: ein Out-of-Band-Celery-Worker, der die am häufigsten angefragten Aggregate unmittelbar nach Schreibvorgängen vorwärmt, sodass die nächste Nutzeranfrage bereits ein Cache-Treffer ist.
Jeder Cache-Key ist nach Mandant + Entität + Version benannt, jeder Lesezugriff meldet einen Treffer/Fehlschlag an Datadog, und jeder Schreibvorgang läuft über ein einziges Invalidierungsmodul, damit ein künftiger Entwickler es nicht unbemerkt umgehen kann.
- Dreistufiges Caching: In-Process-Memoization, Redis-Cluster und vorwärmende Celery-Worker
- Typisierte Pydantic-Cache-Envelopes mit explizitem Versionsfeld für sichere Schema-Evolution
- Keys mit Namensraum (Mandant + Entität + Version), damit Deployments nie Daten unterschiedlicher Struktur ausliefern
- Einziges Invalidierungsmodul – jeder Schreibpfad läuft darüber; keine unbemerkte Umgehung
- Shadow-Read-Rollout mit Cache-gegen-DB-Vergleich bei 10 % des Live-Traffics vor der Umstellung
- Datadog-Dashboards für Trefferquote, p95, Eviction-Rate und Redis-Speicherreserve
- PagerDuty-Alarme bei Rückgang der Trefferquote, Eviction-Spitzen und Redis-Primary-Failover
- k6-Lasttests, die den 3-fachen Spitzen-Traffic nachbilden, mit schriftlichem Kapazitätsmodell