Stratégies de mise à l'échelle des bases de données : réplicas en lecture, partitionnement et au-delà

Faites évoluer votre base de données avec des réplicas en lecture, un partitionnement horizontal, un regroupement de connexions et des stratégies de mise en cache. Couvre PostgreSQL, MySQL et les services de bases de données gérées.

E
ECOSIRE Research and Development Team
|16 mars 20269 min de lecture1.9k Mots|

Stratégies de mise à l'échelle de la base de données : réplicas en lecture, partage et au-delà

Les performances des bases de données constituent le goulot d'étranglement dans 78 % des problèmes de mise à l'échelle des applications Web. Les applications peuvent évoluer horizontalement avec un minimum d'effort, mais les bases de données résistent à la mise à l'échelle horizontale. Les stratégies que vous choisissez pour la mise à l'échelle de la base de données déterminent si votre application dessert 100 ou 100 000 utilisateurs avec des performances acceptables.

Ce guide couvre l'ensemble des stratégies de mise à l'échelle des bases de données, depuis les simples optimisations qui retardent le besoin de mise à l'échelle jusqu'aux techniques avancées telles que le partitionnement horizontal.

Points clés à retenir

  • Optimisez les requêtes et ajoutez des index avant d'ajouter l'infrastructure --- cela résout 60 % des problèmes de performances des bases de données
  • Les réplicas en lecture constituent la stratégie de mise à l'échelle la moins risquée et gèrent 80 % des charges de travail lourdes en lecture.
  • Le pooling de connexions est obligatoire une fois que votre application exécute plus de 10 instances
  • Le partitionnement horizontal est un dernier recours qui introduit une complexité applicative importante

L'échelle d'évolution

Échelle dans cet ordre. Chaque étape est moins chère et moins risquée que la suivante :

Étape 1 : Optimisation des requêtes (gratuite)

Avant d'ajouter une infrastructure, assurez-vous que votre base de données existante fonctionne de manière optimale.

-- Find slow queries in PostgreSQL
SELECT
  calls,
  mean_exec_time::numeric(10,2) AS avg_ms,
  total_exec_time::numeric(10,2) AS total_ms,
  query
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 20;

Optimisations courantes :

  • Ajouter des index manquants pour les colonnes fréquemment filtrées
  • Remplacez SELECT * par des listes de colonnes spécifiques
  • Utilisez EXPLAIN ANALYZE pour identifier les analyses séquentielles sur les grandes tables
  • Ajouter des index composites pour les clauses WHERE multi-colonnes
  • Implémenter la pagination avec la pagination du jeu de clés au lieu de OFFSET
-- Bad: OFFSET pagination (scans all skipped rows)
SELECT * FROM orders ORDER BY created_at DESC LIMIT 20 OFFSET 10000;

-- Good: Keyset pagination (index-only scan)
SELECT * FROM orders
WHERE created_at < '2026-03-15T10:00:00Z'
ORDER BY created_at DESC
LIMIT 20;

Étape 2 : Mise à l'échelle verticale ($)

Augmentez le processeur, la RAM et le stockage sur votre serveur de base de données existant. Cela fait gagner du temps et ne nécessite aucune modification de l’application.

Taille de l'instanceProcesseur virtuelRAMConnexionsCoût mensuel (RDS)
db.t3.medium24 Go10065 $
db.r6g.large216 Go200175 $
db.r6g.xlarge432 Go400350 $
db.r6g.2xlarge864 Go800700 $

La plupart des applications atteignent leur limite à 64 Go de RAM et 8 vCPU. Au-delà de cela, la mise à l’échelle verticale devient prohibitive.

Étape 3 : Regroupement de connexions ($)

Application (50 pods x 20 connections = 1,000 connections)
    |
    v
PgBouncer (25 database connections, transaction pooling)
    |
    v
PostgreSQL (25 active connections, manageable)

Configuration du PgBouncer :

[databases]
app = host=db.example.com port=5432 dbname=production

[pgbouncer]
listen_port = 6432
listen_addr = 0.0.0.0
auth_type = md5
pool_mode = transaction
default_pool_size = 25
max_client_conn = 1000
min_pool_size = 5
reserve_pool_size = 5
reserve_pool_timeout = 3

Étape 4 : Lire les répliques ($$)

Les réplicas en lecture gèrent les requêtes SELECT, déchargeant 60 à 90 % de la charge de la base de données du principal.

Architecture :

Write queries --> Primary database
                      |
              Replication (async)
                      |
                 +----+----+
                 |         |
Read queries --> Replica 1  Replica 2

Routage au niveau de l'application (exemple Drizzle ORM) :

import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

const primaryPool = new Pool({ connectionString: process.env.DATABASE_URL });
const replicaPool = new Pool({ connectionString: process.env.DATABASE_REPLICA_URL });

export const primaryDb = drizzle(primaryPool);
export const replicaDb = drizzle(replicaPool);

// In service code:
// Write operations use primaryDb
async createOrder(data: OrderInput) {
  return primaryDb.insert(orders).values(data).returning();
}

// Read operations use replicaDb
async getOrders(organizationId: string) {
  return replicaDb.select().from(orders)
    .where(eq(orders.organizationId, organizationId))
    .orderBy(desc(orders.createdAt));
}

Considérations relatives au délai de réplication : la réplication asynchrone introduit un délai (généralement de 10 à 100 ms). Immédiatement après une écriture, la lecture à partir du réplica peut renvoyer des données obsolètes. Utilisez le principal pour les lectures qui suivent les écritures dans le même flux utilisateur.

Étape 5 : Mise en cache ($$)

La mise en cache Redis élimine entièrement les requêtes répétées de base de données.

async getProduct(id: string): Promise&lt;Product> {
  const cacheKey = `product:${id}`;

  // Check cache first
  const cached = await this.redis.get(cacheKey);
  if (cached) return JSON.parse(cached);

  // Cache miss: query database
  const product = await this.db.select().from(products)
    .where(eq(products.id, id))
    .limit(1);

  // Cache for 5 minutes
  await this.redis.setex(cacheKey, 300, JSON.stringify(product[0]));

  return product[0];
}

Stratégie d'invalidation du cache : invalider lors de l'écriture. Lorsqu'un produit est mis à jour, supprimez la clé de cache. Utilisez un modèle de mise en cache (l'application gère le cache) plutôt que l'écriture directe (la base de données gère le cache).

Étape 6 : Partage horizontal ($$$)

Le partage distribue les données sur plusieurs instances de base de données en fonction d'une clé de partition.

Stratégie de partageDescriptifIdéal pour
Basé sur le hachageHachez la clé de fragment, répartissez-la uniformémentMême la distribution des données
Basé sur la plageAttribuer des plages aux fragments (par exemple, A-M, N-Z)Séries chronologiques, données géographiques
Basé sur les locatairesUne partition par locataire/organisationSaaS multi-locataires

Quand fragmenter :

  • La base de données unique dépasse 1 To et continue de croître
  • Le débit d'écriture dépasse ce qu'un seul primaire peut gérer
  • Les coûts de mise à l'échelle verticale dépassent 2 000 $/mois sans marge

Quand NE PAS fragmenter :

  • Vous n'avez pas épuisé les étapes 1 à 5
  • Vos données tiennent dans une seule base de données de 500 Go
  • Les requêtes entre fragments sont courantes dans votre application

Optimisations spécifiques à PostgreSQL

Partitionnement (avant le partitionnement)

Le partitionnement des tables PostgreSQL divise les grandes tables en tables physiques plus petites tout en conservant une seule table logique :

-- Partition orders by month
CREATE TABLE orders (
    id UUID PRIMARY KEY,
    organization_id UUID NOT NULL,
    created_at TIMESTAMP NOT NULL,
    total DECIMAL(10,2)
) PARTITION BY RANGE (created_at);

CREATE TABLE orders_2026_01 PARTITION OF orders
    FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');

CREATE TABLE orders_2026_02 PARTITION OF orders
    FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');

CREATE TABLE orders_2026_03 PARTITION OF orders
    FOR VALUES FROM ('2026-03-01') TO ('2026-04-01');

Le partitionnement améliore de 10 à 100 fois les performances des requêtes temporelles sur les grandes tables, car PostgreSQL analyse uniquement les partitions pertinentes.

Passation de l'aspirateur et entretien

-- Check table bloat
SELECT
  schemaname,
  relname,
  n_live_tup,
  n_dead_tup,
  round(n_dead_tup::numeric / greatest(n_live_tup, 1) * 100, 2) AS dead_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;

Configurez autovacuum de manière agressive pour les tables à écriture élevée :

ALTER TABLE orders SET (
  autovacuum_vacuum_threshold = 100,
  autovacuum_vacuum_scale_factor = 0.05,
  autovacuum_analyze_threshold = 50,
  autovacuum_analyze_scale_factor = 0.02
);

Surveillance des performances de la base de données

Suivez ces métriques pour comprendre quand et comment évoluer :

MétriqueOutilSeuil d'alerte
Latence des requêtes (P95)pg_stat_statements>500ms
Connexions activespg_stat_activité>80 % du maximum
Taux de réussite du cachepg_stat_base de données<95%
Retard de réplicationpg_stat_replication>1 seconde
Gonflement de la tablepg_stat_user_tables>20 % de tuples morts
Attente d'E/S disqueiostat/CloudWatch>20 ms

Un taux de réussite du cache inférieur à 95 % est l’indicateur le plus fort que vous avez besoin de plus de mémoire. L’augmentation de shared_buffers et effective_cache_size est souvent moins chère et plus rapide que l’ajout de réplicas en lecture.

Suivi des performances des requêtes

-- Enable pg_stat_statements (postgresql.conf)
-- shared_preload_libraries = 'pg_stat_statements'

-- Find the top 10 most time-consuming queries
SELECT
  queryid,
  calls,
  mean_exec_time::numeric(10,2) AS avg_ms,
  total_exec_time::numeric(10,2) AS total_ms,
  rows,
  query
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

Passez en revue les 10 principales requêtes chaque semaine. L'optimisation d'une seule requête fréquemment exécutée peut réduire la charge globale de la base de données de 10 à 30 %.


Questions fréquemment posées

Comment savoir quand il est temps de passer à l'échelle ?

Surveillez trois métriques : latence des requêtes P95 (alerte à 500 ms), utilisation de la connexion (alerte à 80 %) et utilisation du processeur (alerte à 70 % soutenue). Si vous atteignez régulièrement ces seuils, passez à l’étape suivante de l’échelle d’évolution. Ne pré-optimisez pas --- mettez à l'échelle lorsque les données vous le demandent.

Lire les réplicas ou la mise en cache --- lequel en premier ?

Commencez par la mise en cache. La mise en cache Redis est plus simple à mettre en œuvre, élimine plus de charge (les accès au cache ignorent entièrement la base de données) et coûte moins cher. Ajoutez des réplicas en lecture lorsque votre taux de réussite du cache est déjà supérieur à 80 % mais que la base de données principale est toujours sous la pression des échecs de cache et des opérations d'écriture.

Comment fonctionne la mise à l'échelle de la base de données avec Odoo ?

Odoo utilise exclusivement PostgreSQL. Commencez par l'optimisation des requêtes (Odoo génère des requêtes complexes pour le reporting). Ajoutez PgBouncer pour le regroupement de connexions lorsque vous dépassez 50 utilisateurs simultanés. Utilisez des réplicas en lecture pour les requêtes de reporting (configurez l'option --db-replica d'Odoo). ECOSIRE fournit une optimisation des performances Odoo, y compris le réglage de la base de données.

La base de données gérée (RDS/Cloud SQL) vaut-elle le prix ?

Oui, pour la plupart des entreprises. Les bases de données gérées gèrent les sauvegardes, les correctifs, le basculement et la surveillance automatisés. Le surcoût de 30 à 40 % par rapport à PostgreSQL autogéré est compensé par le temps d'ingénierie que vous gagnez. L'exception concerne les déploiements à grande échelle où le coût supplémentaire d'une grande instance dépasse le coût d'un administrateur de base de données à temps partiel.


Ce qui vient ensuite

La mise à l’échelle des bases de données est un élément d’une stratégie plus large de mise à l’échelle de l’infrastructure. Combinez-le avec l'optimisation CDN pour les actifs statiques, la mise à l'échelle automatique Kubernetes pour les pods d'application et les tests de charge pour valider vos décisions de mise à l'échelle dans des conditions réalistes.

Contactez ECOSIRE pour des conseils en optimisation de bases de données, ou consultez notre guide DevOps pour la feuille de route complète de l'infrastructure.


Publié par ECOSIRE – aider les entreprises à faire évoluer leur infrastructure de données en toute confiance.

E

Rédigé par

ECOSIRE Research and Development Team

Création de produits numériques de niveau entreprise chez ECOSIRE. Partage d'analyses sur les intégrations Odoo, l'automatisation e-commerce et les solutions d'entreprise propulsées par l'IA.

Discutez sur WhatsApp