🔝 Retour au Sommaire
L'adoption massive du cloud computing a transformé la façon dont nous déployons et gérons les bases de données. PostgreSQL, traditionnellement conçu pour fonctionner sur un seul serveur, s'est adapté à cette nouvelle réalité grâce à des solutions cloud-natives et distribuées.
Ce chapitre explore comment PostgreSQL s'intègre dans les architectures cloud modernes, des services managés aux déploiements Kubernetes, en passant par les solutions qui étendent PostgreSQL pour une distribution horizontale à grande échelle.
Cloud-native désigne une approche de conception d'applications qui tire pleinement parti des avantages du cloud computing :
┌─────────────────────────────────────────────────────────────────────────┐
│ Principes Cloud-Native │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Conteneurs │ │ Microservices │ │ Orchestration │ │
│ │ │ │ │ │ │ │
│ │ Packaging │ │ Architecture │ │ Kubernetes │ │
│ │ portable et │ │ découplée et │ │ gestion │ │
│ │ reproductible │ │ scalable │ │ automatisée │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ DevOps/GitOps │ │ Élasticité │ │ Résilience │ │
│ │ │ │ │ │ │ │
│ │ Infrastructure │ │ Scale up/down │ │ Tolérance aux │ │
│ │ as Code │ │ automatique │ │ pannes │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
PostgreSQL a été conçu à l'origine comme une base de données monolithique. Son adaptation au cloud présente des défis spécifiques :
| Défi | Description | Solutions |
|---|---|---|
| État persistant | Les conteneurs sont éphémères, les données ne le sont pas | Volumes persistants, StatefulSets |
| Haute disponibilité | Un pod qui redémarre = indisponibilité | Réplication, failover automatique |
| Scalabilité horizontale | PostgreSQL ne scale pas nativement | Citus, read replicas, sharding |
| Gestion des connexions | Connexions coûteuses en ressources | Connection pooling (PgBouncer) |
| Sauvegarde/Restauration | Complexité dans les environnements distribués | Outils spécialisés (pgBackRest) |
┌─────────────────────────────────────────────────────────────────────────┐
│ Spectre des Options de Déploiement │
│ │
│ Self-Managed Fully │
│ (Control total) Managed │
│ ◄─────────────────────────────────────────────────────────────────► │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ VM / │ │ Docker / │ │Kubernetes│ │ Managed │ │Serverless│ │
│ │ Bare │ │ Compose │ │ Operators│ │ DBaaS │ │ DB │ │
│ │ Metal │ │ │ │ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Plus de ◄───────────────────────────────────► Moins de │
│ contrôle contrôle │
│ │
│ Plus de ◄───────────────────────────────────► Moins de │
│ maintenance maintenance │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Les principaux fournisseurs cloud proposent des services PostgreSQL managés :
| Service | Fournisseur | Points Forts |
|---|---|---|
| Amazon RDS | AWS | Mature, large écosystème |
| Amazon Aurora | AWS | Compatible PostgreSQL, très performant |
| Azure Database | Microsoft | Intégration Azure, Flexible Server |
| Cloud SQL | Simple, intégré GCP | |
| AlloyDB | Haute performance, compatible PostgreSQL | |
| Neon | Neon | Serverless, branching |
| Supabase | Supabase | Backend-as-a-Service, temps réel |
| PlanetScale | - | MySQL (mentionné pour comparaison) |
| CockroachDB | Cockroach Labs | Distribué, compatible PostgreSQL |
Amazon RDS (Relational Database Service) est le service managé PostgreSQL le plus utilisé.
┌─────────────────────────────────────────────────────────────────────────┐
│ Architecture RDS PostgreSQL │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ VPC Client │ │
│ │ │ │
│ │ Application ─────► Security Group ─────► RDS Endpoint │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ AWS Managed Infrastructure │ │
│ │ │ │
│ │ ┌─────────────┐ Réplication ┌─────────────┐ │ │
│ │ │ Primary │ ─────synchrone────► │ Standby │ Multi-AZ │ │
│ │ │ (AZ-a) │ │ (AZ-b) │ │ │
│ │ └──────┬──────┘ └─────────────┘ │ │
│ │ │ │ │
│ │ │ Réplication asynchrone │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Read Replica│ │ Read Replica│ (jusqu'à 15) │ │
│ │ │ (AZ-c) │ │ (Région 2) │ Cross-Region │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Stockage EBS (SSD gp3/io2) avec réplication automatique│ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Géré par AWS : │
│ ✓ Provisioning ✓ Patching ✓ Backups ✓ Monitoring │
│ ✓ Failover ✓ Scaling ✓ Encryption ✓ Compliance │
│ │
└─────────────────────────────────────────────────────────────────────────┘
# Exemple Terraform pour RDS PostgreSQL
resource "aws_db_instance" "postgres" {
identifier = "my-postgres-db"
engine = "postgres"
engine_version = "16.3"
instance_class = "db.r6g.xlarge"
allocated_storage = 100
storage_type = "gp3"
storage_encrypted = true
db_name = "myapp"
username = "admin"
password = var.db_password
# Haute disponibilité
multi_az = true
# Réseau
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.postgres.id]
publicly_accessible = false
# Sauvegardes
backup_retention_period = 7
backup_window = "03:00-04:00"
# Maintenance
maintenance_window = "Mon:04:00-Mon:05:00"
auto_minor_version_upgrade = true
# Performance Insights
performance_insights_enabled = true
# Paramètres PostgreSQL
parameter_group_name = aws_db_parameter_group.postgres.name
}
resource "aws_db_parameter_group" "postgres" {
family = "postgres16"
name = "my-postgres-params"
parameter {
name = "shared_preload_libraries"
value = "pg_stat_statements"
}
parameter {
name = "log_min_duration_statement"
value = "1000"
}
}Aurora est une réécriture du moteur de stockage PostgreSQL par AWS, optimisée pour le cloud.
┌─────────────────────────────────────────────────────────────────────────┐
│ Architecture Aurora PostgreSQL │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Couche Compute │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Writer │ │ Reader │ │ Reader │ │ │
│ │ │ Instance │ │ Instance │ │ Instance │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │ │
│ └──────────┼────────────────┼────────────────┼────────────────────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Couche Stockage Distribuée Aurora │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Storage │ │ Storage │ │ Storage │ │ Storage │ ... │ │
│ │ │ Node │ │ Node │ │ Node │ │ Node │ │ │
│ │ │ (AZ-a) │ │ (AZ-a) │ │ (AZ-b) │ │ (AZ-c) │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ │ • 6 copies des données sur 3 AZs │ │
│ │ • Réplication synchrone au niveau stockage │ │
│ │ • Auto-scaling jusqu'à 128 TB │ │
│ │ • Réparation automatique des blocs corrompus │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
| Caractéristique | Aurora | RDS Standard |
|---|---|---|
| Performance | 3× plus rapide | Baseline |
| Réplication | < 10ms (stockage) | Secondes (streaming) |
| Failover | < 30 secondes | 1-2 minutes |
| Stockage | Auto-scale 128 TB | Manuel, max 64 TB |
| Backups | Continus, PITR | Snapshots planifiés |
| Coût | ~20% plus cher | Baseline |
Aurora Serverless ajuste automatiquement la capacité compute :
# Exemple de configuration Aurora Serverless v2
resource "aws_rds_cluster" "aurora_serverless" {
cluster_identifier = "my-aurora-serverless"
engine = "aurora-postgresql"
engine_mode = "provisioned" # Serverless v2 utilise provisioned
engine_version = "15.4"
serverlessv2_scaling_configuration {
min_capacity = 0.5 # 0.5 ACU minimum (peut descendre à 0 avec pause)
max_capacity = 16 # 16 ACU maximum
}
# ... autres configurations
}
resource "aws_rds_cluster_instance" "aurora_instance" {
identifier = "my-aurora-serverless-instance"
cluster_identifier = aws_rds_cluster.aurora_serverless.id
instance_class = "db.serverless" # Classe spéciale pour Serverless v2
engine = "aurora-postgresql"
}Service PostgreSQL managé simple et fiable de Google Cloud.
# Exemple Terraform pour Cloud SQL
resource "google_sql_database_instance" "postgres" {
name = "my-postgres-instance"
database_version = "POSTGRES_16"
region = "europe-west1"
settings {
tier = "db-custom-4-16384" # 4 vCPU, 16 GB RAM
availability_type = "REGIONAL" # Haute disponibilité
backup_configuration {
enabled = true
point_in_time_recovery_enabled = true
start_time = "03:00"
}
ip_configuration {
ipv4_enabled = false
private_network = google_compute_network.vpc.id
}
database_flags {
name = "log_min_duration_statement"
value = "1000"
}
insights_config {
query_insights_enabled = true
record_application_tags = true
}
}
}AlloyDB est la réponse de Google à Aurora : un PostgreSQL réinventé pour le cloud.
┌─────────────────────────────────────────────────────────────────────────┐
│ Architecture AlloyDB │
│ │
│ Caractéristiques clés : │
│ │
│ • 4× plus rapide que PostgreSQL standard (transactions) │
│ • 100× plus rapide pour les requêtes analytiques │
│ • Séparation compute/stockage (comme Aurora) │
│ • Columnar engine intégré pour l'analytique │
│ • Machine Learning intégré (AlloyDB AI) │
│ • 99.99% SLA disponibilité │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Primary Instance Read Pool (auto-scaling) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Compute │ │ Reader │ │ Reader │ │ Reader │ │ │
│ │ │ (R/W) │ │ #1 │ │ #2 │ │ #N │ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ │ │ │ │ │ │ │
│ │ └──────────────────┴───────────┴───────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Stockage Distribué Intelligent │ │ │
│ │ │ • Log-structured storage │ │ │
│ │ │ • Columnar cache pour analytics │ │ │
│ │ │ • Réplication synchrone multi-zone │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Microsoft propose deux options principales :
# Exemple Terraform pour Azure Flexible Server
resource "azurerm_postgresql_flexible_server" "postgres" {
name = "my-postgres-flexible"
resource_group_name = azurerm_resource_group.main.name
location = "West Europe"
version = "16"
administrator_login = "adminuser"
administrator_password = var.db_password
sku_name = "GP_Standard_D4s_v3"
storage_mb = 131072
delegated_subnet_id = azurerm_subnet.postgres.id
private_dns_zone_id = azurerm_private_dns_zone.postgres.id
high_availability {
mode = "ZoneRedundant"
standby_availability_zone = "2"
}
backup_retention_days = 7
maintenance_window {
day_of_week = 0
start_hour = 3
start_minute = 0
}
}| Critère | RDS | Aurora | Cloud SQL | AlloyDB | Azure Flexible |
|---|---|---|---|---|---|
| Performance | ★★★ | ★★★★★ | ★★★ | ★★★★★ | ★★★★ |
| Coût | $$ | $$$ | $$ | $$$ | $$ |
| Serverless | Non | Oui (v2) | Non | Oui | Oui (preview) |
| Max stockage | 64 TB | 128 TB | 64 TB | 128+ TB | 32 TB |
| Read replicas | 15 | 15 | 10 | Pool auto | 5 |
| Cross-region | Oui | Oui (Global DB) | Oui | Oui | Oui |
Kubernetes offre des avantages pour les bases de données stateful :
- Déclaratif : Infrastructure as Code native
- Auto-healing : Redémarrage automatique des pods défaillants
- Portabilité : Même configuration sur n'importe quel cloud
- Écosystème : Operators spécialisés pour PostgreSQL
┌─────────────────────────────────────────────────────────────────────────┐
│ Concepts Kubernetes pour PostgreSQL │
│ │
│ StatefulSet (pas Deployment!) │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Pod postgres-0 Pod postgres-1 Pod postgres-2 │ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │
│ │ │ Container │ │ Container │ │ Container │ │ │
│ │ │ PostgreSQL │ │ PostgreSQL │ │ PostgreSQL │ │ │
│ │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │
│ │ │ │ │ │ │
│ │ ┌───────▼───────┐ ┌───────▼───────┐ ┌───────▼───────┐ │ │
│ │ │ PVC │ │ PVC │ │ PVC │ │ │
│ │ │ postgres-0 │ │ postgres-1 │ │ postgres-2 │ │ │
│ │ └───────────────┘ └───────────────┘ └───────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Services │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ postgres-rw (ClusterIP) ──► Pointe vers le Primary │ │
│ │ postgres-ro (ClusterIP) ──► Load balance vers les Replicas │ │
│ │ postgres-0 (Headless) ──► Accès direct au pod 0 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Différences avec Deployment : │
│ • Identité stable (postgres-0, postgres-1...) │
│ • Stockage persistant par pod (PVC individuels) │
│ • Démarrage/arrêt ordonnés │
│ • Nom DNS stable (postgres-0.postgres-svc.namespace.svc) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Un Operator est un contrôleur Kubernetes qui automatise la gestion d'applications complexes. Plusieurs operators PostgreSQL existent :
| Operator | Mainteneur | Points Forts |
|---|---|---|
| CloudNativePG | CloudNative PG | CNCF, très actif, natif K8s |
| Zalando Postgres Operator | Zalando | Mature, utilisé en production |
| Crunchy PGO | Crunchy Data | Entreprise, fonctionnalités avancées |
| StackGres | OnGres | Interface UI, extensions packagées |
| Percona Operator | Percona | Multi-cloud, backup intégré |
CloudNativePG est l'operator recommandé par la CNCF (Cloud Native Computing Foundation).
# Installation via kubectl
kubectl apply -f \
https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.22/releases/cnpg-1.22.0.yaml
# Ou via Helm
helm repo add cnpg https://cloudnative-pg.github.io/charts
helm install cnpg cnpg/cloudnative-pg -n cnpg-system --create-namespace # cluster-postgres.yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: my-postgres-cluster
namespace: database
spec:
instances: 3 # 1 primary + 2 replicas
imageName: ghcr.io/cloudnative-pg/postgresql:16.2
# Configuration PostgreSQL
postgresql:
parameters:
shared_buffers: "256MB"
max_connections: "200"
log_min_duration_statement: "1000"
pg_stat_statements.track: all
pg_hba:
- host all all 10.0.0.0/8 scram-sha-256
# Stockage
storage:
size: 50Gi
storageClass: fast-ssd
# Ressources
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2"
# Sauvegardes vers S3
backup:
barmanObjectStore:
destinationPath: s3://my-bucket/backups
s3Credentials:
accessKeyId:
name: aws-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: aws-creds
key: SECRET_ACCESS_KEY
wal:
compression: gzip
retentionPolicy: "7d"
# Monitoring
monitoring:
enablePodMonitor: true
# Affinité pour répartir les pods
affinity:
topologyKey: topology.kubernetes.io/zone# Déployer le cluster
kubectl apply -f cluster-postgres.yaml
# Vérifier l'état
kubectl get clusters -n database
kubectl get pods -n database -l cnpg.io/cluster=my-postgres-cluster # Récupérer les credentials
kubectl get secret my-postgres-cluster-app -n database -o jsonpath='{.data.password}' | base64 -d
# Port-forward pour accès local
kubectl port-forward svc/my-postgres-cluster-rw 5432:5432 -n database
# Ou utiliser le plugin kubectl cnpg
kubectl cnpg psql my-postgres-cluster -n databaseL'operator de Zalando est mature et utilisé en production par de nombreuses entreprises.
# postgresql-cluster.yaml (Zalando)
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
name: my-postgres-cluster
namespace: database
spec:
teamId: "myteam"
numberOfInstances: 3
postgresql:
version: "16"
parameters:
shared_buffers: "256MB"
max_connections: "200"
volume:
size: 50Gi
storageClass: fast-ssd
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2
memory: 2Gi
users:
myapp:
- superuser
- createdb
databases:
myappdb: myapp
patroni:
synchronous_mode: true
synchronous_mode_strict: false
sidecars:
- name: exporter
image: quay.io/prometheuscommunity/postgres-exporter:latest
ports:
- containerPort: 9187┌─────────────────────────────────────────────────────────────────────────┐
│ HA PostgreSQL sur Kubernetes │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Ingress / LoadBalancer │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │
│ │ Service postgres-rw │ │ Service postgres-ro │ │
│ │ (Primary uniquement) │ │ (Read replicas) │ │
│ └──────────────┬──────────────┘ └──────────────┬──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ StatefulSet │ │
│ │ │ │
│ │ Zone A Zone B Zone C │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ postgres-0 │ │ postgres-1 │ │ postgres-2 │ │ │
│ │ │ (Primary) │───►│ (Replica) │ │ (Replica) │ │ │
│ │ │ │ │ │◄───│ │ │ │
│ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │ │
│ │ │ │Patroni/ │ │ │ │Patroni/ │ │ │ │Patroni/ │ │ │ │
│ │ │ │ CNPG │ │ │ │ CNPG │ │ │ │ CNPG │ │ │ │
│ │ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │ │
│ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ │
│ │ │ PVC │ │ PVC │ │ PVC │ │ │
│ │ │ 50Gi │ │ 50Gi │ │ 50Gi │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Failover automatique : │
│ 1. Patroni/CNPG détecte la panne du primary │
│ 2. Élection d'un nouveau primary parmi les replicas │
│ 3. Mise à jour du Service postgres-rw vers le nouveau primary │
│ 4. Temps de failover : ~10-30 secondes │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Une base de données distribuée répartit les données sur plusieurs nœuds, offrant :
- Scalabilité horizontale : Ajouter des nœuds pour augmenter la capacité
- Haute disponibilité : Tolérance aux pannes de nœuds
- Distribution géographique : Données proches des utilisateurs
┌─────────────────────────────────────────────────────────────────────────┐
│ PostgreSQL Standard vs Distribué │
│ │
│ PostgreSQL Standard PostgreSQL Distribué (ex: Citus) │
│ │
│ ┌─────────────────┐ ┌──────────────────┐ │
│ │ │ │ Coordinator │ │
│ │ Single Node │ │ (routage) │ │
│ │ │ └────────┬─────────┘ │
│ │ Toutes les │ │ │
│ │ données ici │ ┌────────┼────────┐ │
│ │ │ ▼ ▼ ▼ │
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ └─────────────────┘ │ Worker │ │ Worker │ │ Worker │ │
│ │ Node 1 │ │ Node 2 │ │ Node 3 │ │
│ │ Shard A │ │ Shard B │ │ Shard C │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Scale vertical Scale horizontal │
│ (plus gros serveur) (plus de serveurs) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Citus transforme PostgreSQL en base de données distribuée tout en conservant la compatibilité SQL.
┌─────────────────────────────────────────────────────────────────────────┐
│ Architecture Citus │
│ │
│ Application │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Coordinator Node │ │
│ │ │ │
│ │ • Reçoit les requêtes SQL │ │
│ │ • Parse et planifie la distribution │ │
│ │ • Agrège les résultats des workers │ │
│ │ • Stocke les métadonnées de distribution │ │
│ │ │ │
│ └───────────────────────────┬─────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────┼───────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Worker Node │ │ Worker Node │ │ Worker Node │ │
│ │ │ │ │ │ │ │
│ │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │ │
│ │ │ Shard 1 │ │ │ │ Shard 2 │ │ │ │ Shard 3 │ │ │
│ │ │ Shard 4 │ │ │ │ Shard 5 │ │ │ │ Shard 6 │ │ │
│ │ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │ │
│ │ │ │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
│ Types de tables : │
│ • Distributed : Shardées par clé de distribution │
│ • Reference : Répliquées sur tous les workers (petites tables) │
│ • Local : Tables normales sur le coordinator │
│ │
└─────────────────────────────────────────────────────────────────────────┘
-- Activer l'extension Citus
CREATE EXTENSION citus;
-- Ajouter des workers au cluster
SELECT citus_add_node('worker1.example.com', 5432);
SELECT citus_add_node('worker2.example.com', 5432);
SELECT citus_add_node('worker3.example.com', 5432);
-- Créer une table distribuée
CREATE TABLE events (
tenant_id INTEGER,
event_id BIGSERIAL,
event_type VARCHAR(50),
event_data JSONB,
created_at TIMESTAMP DEFAULT NOW(),
PRIMARY KEY (tenant_id, event_id)
);
-- Distribuer la table par tenant_id (64 shards par défaut)
SELECT create_distributed_table('events', 'tenant_id');
-- Créer une table de référence (répliquée partout)
CREATE TABLE event_types (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE
);
SELECT create_reference_table('event_types');
-- Les requêtes SQL standard fonctionnent !
INSERT INTO events (tenant_id, event_type, event_data)
VALUES (1, 'page_view', '{"url": "/home"}');
SELECT tenant_id, COUNT(*)
FROM events
WHERE created_at > NOW() - INTERVAL '1 day'
GROUP BY tenant_id;
-- Requête sur un seul tenant (routée vers un seul shard)
SELECT * FROM events WHERE tenant_id = 42;Azure propose Citus en tant que service managé :
Azure Database for PostgreSQL - Hyperscale (Citus)
Caractéristiques :
• Citus managé par Microsoft
• Auto-scaling des workers
• Backups automatiques
• Monitoring intégré
• SLA 99.99%
YugabyteDB est une base de données distribuée compatible PostgreSQL, conçue from scratch pour le cloud.
┌─────────────────────────────────────────────────────────────────────────┐
│ Architecture YugabyteDB │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ YSQL Layer │ │
│ │ (Compatible PostgreSQL Wire Protocol) │ │
│ │ │ │
│ │ • Parser PostgreSQL │ │
│ │ • Optimizer │ │
│ │ • Extensions PostgreSQL supportées │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ DocDB (Storage Layer) │ │
│ │ │ │
│ │ • Inspiré de Google Spanner │ │
│ │ • Stockage clé-valeur distribué │ │
│ │ • Consensus Raft pour la réplication │ │
│ │ • Transactions distribuées (2PC) │ │
│ │ • Sharding automatique │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Tablet │ │ Tablet │ │ Tablet │ │ Tablet │ ... │ │
│ │ │(Shard) │ │(Shard) │ │(Shard) │ │(Shard) │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Répartition géographique : │
│ │
│ US-East EU-West Asia-Pacific │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ YB Node │ ◄──► │ YB Node │ ◄───► │ YB Node │ │
│ │ (RF=3) │ │ (RF=3) │ │ (RF=3) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
| Caractéristique | Description |
|---|---|
| Compatibilité | PostgreSQL wire protocol + SQL |
| Distribution | Sharding automatique |
| Réplication | Raft consensus (synchrone) |
| Consistance | Strong consistency (CP dans CAP) |
| Transactions | Distribuées ACID |
| Géo-distribution | Multi-région native |
-- YugabyteDB utilise la syntaxe PostgreSQL standard
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE,
name VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW()
);
-- Tablespaces pour le placement géographique
CREATE TABLESPACE eu_west WITH (
replica_placement = '{"num_replicas": 3, "placement_blocks": [
{"cloud": "aws", "region": "eu-west-1", "zone": "eu-west-1a", "min_num_replicas": 1},
{"cloud": "aws", "region": "eu-west-1", "zone": "eu-west-1b", "min_num_replicas": 1},
{"cloud": "aws", "region": "eu-west-1", "zone": "eu-west-1c", "min_num_replicas": 1}
]}'
);
CREATE TABLE eu_users (LIKE users) TABLESPACE eu_west;| Critère | Citus | YugabyteDB | CockroachDB | Vitess |
|---|---|---|---|---|
| Base | PostgreSQL | Custom (compat PG) | Custom (compat PG) | MySQL |
| Compatibilité PG | ★★★★★ | ★★★★ | ★★★ | N/A |
| Transactions distribuées | Limitées | Oui | Oui | Limitées |
| Géo-distribution | Manuel | Native | Native | Manuel |
| Complexité | Faible | Moyenne | Moyenne | Élevée |
| Cas d'usage | Multi-tenant SaaS | Global apps | Global apps | Large scale |
Le serverless PostgreSQL élimine la gestion de l'infrastructure :
- Auto-scaling : Capacité ajustée automatiquement à la charge
- Pay-per-use : Facturation à l'utilisation réelle
- Scale-to-zero : Aucun coût quand inactif
- Instant provisioning : Base disponible en secondes
Neon a réinventé PostgreSQL pour le serverless avec une architecture de séparation compute/stockage.
┌─────────────────────────────────────────────────────────────────────────┐
│ Architecture Neon │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Compute Layer │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Compute Endpoint│ │ Compute Endpoint│ (scale 0→N) │ │
│ │ │ (PostgreSQL) │ │ (PostgreSQL) │ │ │
│ │ │ "main" │ │ "dev-branch" │ │ │
│ │ └────────┬────────┘ └────────┬────────┘ │ │
│ │ │ │ │ │
│ └────────────┼────────────────────┼───────────────────────────────┘ │
│ │ │ │
│ │ Neon Proxy │ │
│ │ (connection pool) │ │
│ │ │ │
│ └─────────┬──────────┘ │
│ │ │
│ ┌──────────────────────▼──────────────────────────────────────────┐ │
│ │ Pageserver │ │
│ │ (Stockage virtualisé) │ │
│ │ │ │
│ │ • Sert les pages à la demande │ │
│ │ • Cache intelligent │ │
│ │ • Copy-on-write pour le branching │ │
│ │ │ │
│ └──────────────────────┬──────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼──────────────────────────────────────────┐ │
│ │ Safekeepers │ │
│ │ (WAL distribué, Paxos) │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ SK1 │ │ SK2 │ │ SK3 │ (quorum = 2/3) │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ └──────────────────────┬──────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼──────────────────────────────────────────┐ │
│ │ Object Storage (S3) │ │
│ │ (Stockage durable et économique) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ Fonctionnalités uniques : │
│ • Branching instantané (comme Git pour les données!) │
│ • Scale-to-zero (0 coût quand inactif) │
│ • Point-in-time restore à la seconde │
│ • Connection pooling intégré │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Le branching permet de créer des copies instantanées de votre base :
# Créer une branche pour le développement
neon branch create --name dev-feature-123 --parent main
# La branche est disponible immédiatement avec toutes les données
# Aucune copie physique n'est faite (copy-on-write)
# Connexion à la branche
psql "postgres://user:pass@dev-feature-123.neon.tech/mydb"Cas d'usage du branching :
- Preview environments : Une branche par PR
- Tests : Tester les migrations sur une copie
- Analytics : Requêtes lourdes sur une branche isolée
- Debug : Reproduire un bug avec les vraies données
Supabase est une alternative open-source à Firebase, basée sur PostgreSQL.
┌─────────────────────────────────────────────────────────────────────────┐
│ Architecture Supabase │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Supabase Studio │ │
│ │ (Interface d'administration web) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Auth (GoTrue) │ │ Storage (S3) │ │ Realtime │ │
│ │ │ │ │ │ (WebSocket) │ │
│ │ • JWT tokens │ │ • File upload │ │ • Subscriptions│ │
│ │ • OAuth/SAML │ │ • CDN │ │ • Broadcasts │ │
│ │ • Row Level │ │ • Policies │ │ • Presence │ │
│ │ Security │ │ │ │ │ │
│ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │ │
│ └────────────────────┼────────────────────┘ │
│ │ │
│ ┌─────────────────────────────▼───────────────────────────────────┐ │
│ │ PostgREST │ │
│ │ (API REST auto-générée depuis le schéma) │ │
│ └─────────────────────────────┬───────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────▼───────────────────────────────────┐ │
│ │ PostgreSQL │ │
│ │ │ │
│ │ Extensions incluses : │ │
│ │ • pgvector (IA/ML) │ │
│ │ • PostGIS (géospatial) │ │
│ │ • pg_graphql │ │
│ │ • pgsodium (encryption) │ │
│ │ • pg_stat_statements │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://xxx.supabase.co',
'your-anon-key'
)
// Requête simple
const { data, error } = await supabase
.from('users')
.select('*')
.eq('status', 'active')
// Insertion
const { data, error } = await supabase
.from('posts')
.insert({ title: 'Hello World', user_id: 1 })
.select()
// Temps réel
supabase
.channel('posts')
.on('postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'posts' },
(payload) => console.log('New post:', payload.new)
)
.subscribe()
// Recherche vectorielle (pgvector)
const { data } = await supabase.rpc('match_documents', {
query_embedding: [0.1, 0.2, ...],
match_threshold: 0.8,
match_count: 5
})| Critère | Neon | Supabase | PlanetScale* | Aurora Serverless |
|---|---|---|---|---|
| Base | PostgreSQL | PostgreSQL | MySQL | PostgreSQL |
| Scale-to-zero | Oui | Non (plan Pro) | Oui | Oui (v2) |
| Branching | Oui | Non | Oui | Non |
| Temps réel | Non | Oui | Non | Non |
| Auth intégré | Non | Oui | Non | Non |
| Open source | Oui | Oui | Non | Non |
| Prix entrée | Gratuit | Gratuit | Gratuit | ~$50/mois |
*PlanetScale est MySQL mais souvent comparé
Dans le cloud, les connexions sont précieuses. Utilisez toujours un pooler.
┌─────────────────────────────────────────────────────────────────────────┐
│ Sans vs Avec Connection Pooling │
│ │
│ SANS POOLING (problème) │
│ │
│ Lambda/Container 1 ────┐ │
│ Lambda/Container 2 ────┼────► PostgreSQL (max_connections = 100) │
│ Lambda/Container 3 ────┤ Épuisement rapide des connexions! │
│ ... │ │
│ Lambda/Container 100 ──┘ │
│ │
│ AVEC POOLING (solution) │
│ │
│ Lambda/Container 1 ────┐ ┌─────────────┐ │
│ Lambda/Container 2 ────┼─────►│ PgBouncer │────► PostgreSQL │
│ Lambda/Container 3 ────┤ │ (pooler) │ (20 connexions) │
│ ... │ │ 1000 clients│ │
│ Lambda/Container 1000 ─┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
# Déploiement PgBouncer sur Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: pgbouncer
spec:
replicas: 2
template:
spec:
containers:
- name: pgbouncer
image: bitnami/pgbouncer:latest
env:
- name: POSTGRESQL_HOST
value: "postgres-primary"
- name: POSTGRESQL_DATABASE
value: "mydb"
- name: PGBOUNCER_POOL_MODE
value: "transaction"
- name: PGBOUNCER_MAX_CLIENT_CONN
value: "1000"
- name: PGBOUNCER_DEFAULT_POOL_SIZE
value: "20"# Kubernetes Secret pour les credentials
apiVersion: v1
kind: Secret
metadata:
name: postgres-credentials
type: Opaque
stringData:
POSTGRES_USER: "myuser"
POSTGRES_PASSWORD: "super-secret-password"
POSTGRES_DB: "mydb"
---
# Utilisation dans un Pod
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: postgres-credentials
key: POSTGRES_PASSWORD# AWS Secrets Manager
aws secretsmanager create-secret \
--name prod/postgres/credentials \
--secret-string '{"username":"admin","password":"xxx"}'
# Rotation automatique
aws secretsmanager rotate-secret \
--secret-id prod/postgres/credentials \
--rotation-lambda-arn arn:aws:lambda:...# Stack d'observabilité cloud-native
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ Métriques Logs Traces │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Prometheus │ │ Loki / │ │ Jaeger / │ │
│ │ + postgres │ │ CloudWatch │ │ Tempo │ │
│ │ exporter │ │ │ │ │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └───────────────────────────┼───────────────────────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ Grafana │ │
│ │ (Dashboard) │ │
│ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘# ServiceMonitor pour Prometheus (avec postgres_exporter)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: postgres-monitor
spec:
selector:
matchLabels:
app: postgres
endpoints:
- port: metrics
interval: 30s
path: /metrics┌────────────────────────────────────────────────────────────────────────┐
│ Architecture DR Multi-Cloud │
│ │
│ Cloud Principal (AWS) Cloud DR (GCP) │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Region us-east-1 │ │ Region us-central │ │
│ │ │ │ │ │
│ │ ┌─────────────┐ │ WAL │ ┌─────────────┐ │ │
│ │ │ Primary │────┼──────────────┼─►│ Standby │ │ │
│ │ │ (Aurora) │ │ Streaming │ │ (Cloud SQL) │ │ │
│ │ └─────────────┘ │ │ └─────────────┘ │ │
│ │ │ │ │ │ │
│ │ ▼ │ │ │ │
│ │ ┌─────────────┐ │ │ ┌──────────────┐ │ │
│ │ │ S3 Bucket │────┼──────────────┼─►│ GCS Bucket │ │ │
│ │ │ (Backups) │ │ Cross-cloud │ │ (Backups) │ │ │
│ │ └─────────────┘ │ replication │ └──────────────┘ │ │
│ │ │ │ │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ RPO (Recovery Point Objective) : < 1 minute │
│ RTO (Recovery Time Objective) : < 15 minutes │
│ │
└────────────────────────────────────────────────────────────────────────┘
Ce chapitre a exploré PostgreSQL dans les architectures cloud modernes :
| Concept | Ce qu'il faut retenir |
|---|---|
| Services managés | RDS, Aurora, Cloud SQL, AlloyDB |
| Kubernetes | Operators (CNPG, Zalando), StatefulSets |
| Distribué | Citus, YugabyteDB pour le scale horizontal |
| Serverless | Neon, Supabase, Aurora Serverless v2 |
| Bonnes pratiques | Pooling, secrets, observabilité |
- Les services managés simplifient l'opérationnel mais réduisent le contrôle
- Kubernetes + Operators offrent un bon équilibre contrôle/automatisation
- Citus est idéal pour le multi-tenant SaaS
- YugabyteDB et CockroachDB pour les applications globales
- Neon révolutionne le développement avec le branching
- Le connection pooling est obligatoire dans le cloud
┌─────────────────────────────────────────────────────────────────────────┐
│ Arbre de Décision │
│ │
│ Besoin de scale horizontal ? │
│ ├─► Oui ──► Transactions distribuées importantes ? │
│ │ ├─► Oui ──► YugabyteDB / CockroachDB │
│ │ └─► Non ──► Citus (surtout si multi-tenant) │
│ │ │
│ └─► Non ──► Besoin de simplicité maximale ? │
│ ├─► Oui ──► Service managé (RDS, Cloud SQL) │
│ └─► Non ──► Besoin de contrôle ? │
│ ├─► Oui ──► Kubernetes + Operator │
│ └─► Non ──► Serverless (Neon, Supabase) │
│ │
└─────────────────────────────────────────────────────────────────────────┘