Mise à l'échelle de la base de données : éviter les goulots d'étranglement
La base de données est toujours le seul point d’échec de la mise à l’échelle. Stratégies d'optimisation Postgres, de répliques en lecture et de partage.
Le maillon le plus faible du monolithe
Vous pouvez faire évoluer vos serveurs Frontend à l’infini (il suffit d’ajouter plus de nœuds derrière l’équilibreur de charge). Vous pouvez faire évoluer vos serveurs API à l’infini (fonctions Serverless). Vous ne pouvez pas faire évoluer facilement votre base de données principale. Il n’y a (généralement) qu’une une source de vérité. Un disque. Un processus maître. Lorsque le trafic augmente, le processeur atteint 100 % et la latence des requêtes passe de 10 ms à 10 000 ms. Le site meurt. La mise à l’échelle de la base de données est le problème le plus difficile de l’ingénierie backend.
Pourquoi Maison Code en parle
Chez Maison Code, nous voyons des startups valides mourir à cause de SQL. Ils écrivent du code comme « SELECT * FROM Orders ». Cela fonctionne bien avec 100 commandes. Cela plante le serveur avec 1 000 000 de commandes. Nous optimisons les bases de données pour High Cardinality et High Throughput. Nous savons que « Ajouter des index » ne suffit pas. Vous avez besoin de changements d’architecture (mise en cache, réplication, partitionnement).
Stratégie 1 : Indexation (le fruit à portée de main)
La plupart des problèmes de performances sont dus à des index manquants.
Scénario : Recherche d’un utilisateur par e-mail.
Requête : SELECT * FROM utilisateurs WHERE email = 'alex@example.com'.
Sans index : la base de données analyse 1 000 000 de lignes (analyse séquentielle). SUR).
Avec Index (B-Tree) : La base de données accède directement à l’e-mail. O (log N).
Coût : Les index ralentissent les écritures (INSERT/UPDATE), car l’arborescence des index doit être mise à jour.
Règle : colonnes d’index utilisées dans WHERE, JOIN et ORDER BY.
Stratégie 2 : Mise en cache (Redis)
La requête la plus rapide est celle que vous ne faites pas. SQL est lent (E/S disque, calculs CPU). Redis est rapide (In-Memory, Key-Value). Modèle : Cache de recherche.
fonction asynchrone getProduct(id) {
// 1. Vérifier le cache
const cached = wait redis.get(`product:${id}`);
if (mis en cache) return JSON.parse(cached);
// 2. Requête DB (lent)
const product = wait db.query('SELECT * FROM products WHERE id = ?', [id]);
// 3. Enregistrer dans le cache (TTL 5 minutes)
wait redis.set(`product:${id}`, JSON.stringify(product), 'EX', 300);
retourner le produit ;
}
Cela décharge 90 % du trafic de lecture de la base de données.
Stratégie 3 : Lire les répliques
Même avec la mise en cache, les lectures peuvent surcharger le processeur. Solution : créez des copies de la base de données (répliques).
- Nœud principal : gère les écritures (INSERT, UPDATE, DELETE). Synchronise les modifications avec les répliques (Async).
- Nœuds de réplication : gérer les lectures (SELECT). Compromis : Retard de réplication. L’utilisateur met à jour son profil. Ils actualisent la page immédiatement. Ils ont touché une réplique qui n’a pas encore reçu la mise à jour. Ils voient l’ancien profil. Correction : “Lisez vos propres écritures”. Pour l’utilisateur actuel, forcez la lecture à partir du primaire. Pour les données publiques, lisez depuis Replica.
Stratégie 4 : Regroupement de connexions (PgBouncer)
Postgres a une limite sur les connexions simultanées (par exemple, maintenir 100). Les fonctions sans serveur (Lambda) génèrent 1 000 instances. Si 1 000 instances tentent d’ouvrir une connexion, Postgres plante. Solution : Un proxy (PgBouncer / Supabase Pooler). Le proxy contient 100 connexions ouvertes à la base de données. Les 1 000 Lambdas parlent au Proxy. Le proxy met les requêtes en file d’attente et les exécute en utilisant les 100 connexions. Ceci est obligatoire pour les architectures Serverless.
Stratégie 5 : Partitionnement vertical (fractionnement des tables)
Le tableau Utilisateurs contient bio (texte, énorme) et last_login (date, petit).
Si vous interrogez fréquemment last_login, mais que bio rend la taille de la ligne énorme, la base de données lit trop de données sur le disque.
Partagez-le :
Tableau User_Core (id, email, mot de passe, last_login).
Tableau User_Profile (id, bio, avatar).
Désormais, « SELECT last_login FROM User_Core » est extrêmement rapide car davantage de lignes tiennent dans les pages RAM.
6. Vues matérialisées : pré-calcul du succès
“Montrez-moi le chiffre d’affaires total pour 2024.”
SELECT SUM(montant) FROM commandes WHERE année = 2024.
Cela analyse 10 millions de lignes. Cela prend 5 secondes.
Solution : vue matérialisée.
CRÉER UNE VUE MATÉRIALISÉE annual_revenue AS SELECT ...
Postgres calcule le résultat et l’enregistre sur le disque en tant que table physique.
L’interroger prend 1 ms.
Compromis : les données sont obsolètes. Vous devez « ACTUALISER LA VUE MATÉRIELLE » périodiquement (par exemple, toutes les heures).
Parfait pour les tableaux de bord où le « temps réel » n’est pas strictement requis.
7. Mise à l’échelle automatique de la base de données (Aurora sans serveur)
Que faire si vous ne souhaitez pas gérer les répliques ? Amazon Aurora sans serveur v2. Il ajoute automatiquement du CPU/RAM lorsque le trafic augmente et diminue lorsque le trafic diminue. Il évolue par incréments fractionnaires (ACU). Il vous offre effectivement la promesse « Infinite Scaling » de NoSQL, mais avec une compatibilité SQL totale. C’est cher, mais moins cher que d’embaucher un administrateur de base de données pour provisionner manuellement les réplicas en lecture à 3 heures du matin.
9. Données de séries chronologiques (TimescaleDB)
“Enregistrez chaque page vue.”
“Enregistrez chaque lecture du thermomètre.”
Postgres standard s’étouffe lors de l’insertion de 10 000 lignes/seconde dans une seule table.
Les index deviennent fragmentés.
Solution : TimescaleDB (extension Postgres).
Il partitionne automatiquement les données par heure (« Hypertables »).
commandes_2024_01, commandes_2024_02.
Vous l’interrogez sous la forme d’une seule table « commandes », mais physiquement, il s’agit de petits morceaux.
La suppression des anciennes données est instantanée (« DROP TABLEorders_2020 »). « SUPPRIMER DES commandes OÙ année = 2020 » prend des heures.
10. Stratégies de partitionnement avancées
Le partitionnement vertical divise les colonnes.
Partitionnement horizontal divise les lignes.
Par région : users_eu, users_us.
Cela aide avec le RGPD (Data Residency).
“Les données européennes ne quittent jamais le serveur de l’UE.”
Le partitionnement déclaratif Postgres rend cela gérable.
C’est ainsi que nous adaptons les applications SaaS à des millions de locataires sans acheter de Mainframe.
11. Le point de vue du sceptique
“Utilisez simplement DynamoDB / NoSQL. Il évolue à l’infini.” Contre-point : NoSQL met à l’échelle les écritures, mais il échoue au niveau des données relationnelles. “Montrez-moi toutes les commandes des utilisateurs parisiens qui ont acheté des chaussures rouges.” En SQL : une requête. Dans NoSQL : un cauchemar de jointures côté application et de récupérations multiples. La plupart des données du commerce électronique sont relationnelles. Tenez-vous-en à SQL (Postgres) jusqu’à ce que vous atteigniez l’échelle de Google.
##FAQ
Q : Quand utiliser Sharding ? R : Presque jamais. Le partage (répartition des données sur plusieurs serveurs en fonction de l’ID utilisateur) est extrêmement complexe. Vous perdez les transactions ACID entre les fragments. Ne partagez pas avant d’avoir > 10 To de données. La mise à l’échelle verticale (Bigger Server) fonctionne étonnamment bien jusqu’à présent.
Q : ORM contre SQL brut ? R : Prisma/Drizzle (ORM) pour la productivité. Raw SQL pour des rapports complexes ou des requêtes super optimisées. Les ORM modernes sont suffisamment performants pour 99 % des requêtes.
Conclusion
La base de données est le cœur de votre pile.
S’il arrête de battre, l’application meurt.
Traitez-le avec respect. Indexez vos clés étrangères. Mettez en cache vos chemins chauds.
Et n’exécutez jamais, au grand jamais, DROP TABLE le vendredi.
Étouffement de la base de données ?
Si vos requêtes expirent ou si votre processeur est en panne, Maison Code peut optimiser votre schéma. Nous analysons les plans de requête, mettons en œuvre des stratégies de mise en cache et concevons des jeux de réplicas.
Les requêtes sont trop lentes ?
Nous optimisons l’architecture de base de données à l’aide de l’indexation, de la mise en cache et des répliques en lecture pour gérer une échelle massive. Embauchez nos architectes.