Le défi
Un SaaS B2B en forte croissance se heurtait à un mur. Son API Python/FastAPI alimentait des tableaux de bord pour des milliers de comptes à licences, et le chemin de lecture était devenu un enchevêtrement de requêtes ORM N+1, de vérifications de permissions répétées et de consultations de feature flags à chaque requête. La latence p95 des points de terminaison les plus sollicités était passée de 380 ms au lancement à 1,8 s, le CPU RDS était saturé à 80 % pendant les heures de bureau, et l’équipe d’ingénierie chiffrait déjà une montée en gamme verticale de RDS qui aurait ajouté environ 3 400 $/mois à la facture.
Pire, la lenteur était invisible pour la moitié de la clientèle car le tableau de bord s’affiche progressivement — le temps que les clients se plaignent, l’équipe avait déjà perdu un renouvellement d’entreprise à cause de « le tableau de bord semble cassé ». L’équipe avait besoin d’une solution en quelques semaines, pas d’une replateformisation de six mois.
Notre solution
Nous avons placé une couche de cache Redis rigoureuse à trois niveaux devant les chemins de lecture les plus sollicités et remodelé le modèle de données pour qu’il puisse être mis en cache en toute sécurité. L’investissement a porté sur la conception des clés de cache, les contrats d’invalidation et l’observabilité — et non sur l’ajout aveugle de mémoire.
Niveau 1 : mémoïsation par requête dans le conteneur de dépendances FastAPI, éliminant les consultations en double au sein d’une même requête.
Niveau 2 : un cluster Redis 7 partagé (mode cluster, AWS ElastiCache) contenant les lectures chaudes — ensembles de permissions, feature flags, métadonnées de compte, agrégats de tableau de bord — avec des TTL explicites et une enveloppe Pydantic typée pour que les charges mises en cache soient versionnées et évolutives en toute sécurité.
Niveau 3 : un worker Celery hors bande qui préchauffe les agrégats les plus demandés immédiatement après les écritures, de sorte que la requête suivante de l’utilisateur soit déjà un succès de cache.
Chaque clé de cache est préfixée par tenant + entité + version, chaque lecture enregistre un succès/échec dans Datadog, et chaque écriture passe par un module d’invalidation unique afin qu’un futur ingénieur ne puisse pas le contourner silencieusement.
- Cache à trois niveaux : mémoïsation en processus, cluster Redis et workers Celery de préchauffage
- Enveloppes de cache Pydantic typées avec champ de version explicite pour une évolution de schéma sûre
- Clés préfixées (tenant + entité + version) pour que les déploiements ne servent jamais des données de formes mixtes
- Module d’invalidation unique — tous les chemins d’écriture y passent ; aucun contournement silencieux
- Déploiement en lecture miroir avec comparaison cache/BDD sur 10 % du trafic réel avant la bascule
- Tableaux de bord Datadog pour le taux de succès, la p95, le taux d’éviction et la marge de mémoire Redis
- Alertes PagerDuty sur la baisse du taux de succès, les pics d’éviction et le basculement du primaire Redis
- Tests de charge k6 reproduisant 3 fois le trafic de pointe, avec un modèle de capacité écrit