- OpenAI a massivement étendu son infrastructure PostgreSQL pour faire face à la forte hausse du trafic de ChatGPT et de l’API, en traitant plusieurs millions de QPS avec un serveur flexible Azure PostgreSQL unique et environ 50 réplicas de lecture
- Tout en conservant une architecture optimisée pour les workloads centrés sur la lecture, une partie des workloads a été migrée vers Azure Cosmos DB afin de réduire la charge d’écriture
- Diverses optimisations, comme le pooling de connexions avec PgBouncer, le verrouillage de cache, le rate limiting et l’isolation des workloads, ont permis d’améliorer la stabilité et la latence
- Pour dépasser les limites d’une architecture à primaire unique, des tests ont été menés en parallèle sur une configuration de haute disponibilité (HA), le hot standby et la réplication en cascade (cascading replication)
- Cette approche a permis d’atteindre une disponibilité de 99,999 % et une latence p99 de l’ordre de quelques dizaines de millisecondes, tout en ouvrant la voie à une future extension vers un PostgreSQL shardé ou des systèmes distribués
Vue d’ensemble de l’extension de PostgreSQL
- PostgreSQL est le système de données central de ChatGPT et de l’API OpenAI, avec une charge multipliée par plus de 10 au cours de l’année écoulée
- Une instance primaire unique et environ 50 réplicas de lecture répartis dans le monde traitent les requêtes de 800 millions d’utilisateurs
- Tout en conservant une architecture centrée sur la lecture, une partie des workloads a été déplacée vers Azure Cosmos DB pour alléger la charge d’écriture
- L’ajout de nouvelles tables est interdit, et les nouveaux workloads sont par défaut placés sur un système shardé
Défis de l’architecture à primaire unique et réponses apportées
- Une architecture à rédacteur unique pose des limites de scalabilité en écriture et un problème de point unique de défaillance (SPOF)
- Le trafic de lecture est réparti sur les réplicas, tandis que le trafic d’écriture pour les workloads shardables est déplacé vers Cosmos DB
- Une configuration de haute disponibilité via hot standby permet une promotion rapide en cas de panne (failover)
- Lors de pics soudains de charge en lecture, des ratés de cache ont provoqué une saturation CPU
- Un mécanisme de verrouillage du cache a été introduit pour éviter les requêtes dupliquées sur une même clé
Optimisation des requêtes et des ressources
- Des requêtes complexes à multiples jointures monopolisaient excessivement le CPU et provoquaient de la latence
- Les SQL inefficaces générées par l’ORM ont été revues, et les logiques de jointure complexes ont été déplacées vers la couche applicative
- Le paramètre idle_in_transaction_session_timeout a été utilisé pour éviter les requêtes inactives de longue durée
- Pour résoudre le problème du "noisy neighbor", le trafic a été séparé sur des instances selon le niveau de priorité
- Cette isolation empêche les requêtes de faible priorité d’affecter les services à haute priorité
Gestion des connexions et contrôle de charge
- Pour contourner la limite de 5 000 connexions d’Azure PostgreSQL, PgBouncer a été introduit comme couche proxy
- La réutilisation des connexions a réduit le temps moyen de connexion de 50 ms à 5 ms
- Afin de réduire la latence réseau interrégionale, le proxy, les clients et les réplicas ont été placés dans la même région
- Le rate limiting a été appliqué aux niveaux application, proxy et requête afin d’éviter les brusques explosions de trafic
- La couche ORM a également été améliorée pour pouvoir bloquer certains digest de requêtes spécifiques
Gestion de la réplication et des changements de schéma
- Comme le primaire doit streamer les logs WAL à tous les réplicas, l’augmentation de leur nombre accroît la charge réseau
- La réplication en cascade (cascading replication) est actuellement testée en collaboration avec l’équipe Azure
- Des réplicas intermédiaires transmettent le WAL à des réplicas en aval, ouvrant la possibilité de dépasser 100 réplicas
- Les changements de schéma qui provoquent une réécriture complète de table (full table rewrite) sont interdits
- Seuls des changements légers sont autorisés dans une fenêtre de timeout de 5 secondes, et la création ou suppression d’index peut être effectuée de manière concurrente
- Même lors des backfills, des limites de débit strictes sont appliquées
Résultats et feuille de route
- PostgreSQL traite plusieurs millions de QPS, avec une latence de quelques dizaines de millisecondes (p99) et une disponibilité de 99,999 %
- Au cours des 12 derniers mois, un seul incident SEV-0 a été enregistré (lors du lancement de ChatGPT ImageGen)
- Les workloads restants centrés sur l’écriture sont eux aussi migrés progressivement vers Cosmos DB
- Une fois la réplication en cascade finalisée, l’objectif est de renforcer encore la scalabilité et la stabilité des réplicas
- À plus long terme, l’adoption d’un PostgreSQL shardé ou d’un autre système distribué est à l’étude
1 commentaires
Réactions sur Hacker News
Dans PostgreSQL, les requêtes idle de longue durée posent souvent problème
Dans le code de notre entreprise, il y avait beaucoup de schémas du type « connexion → début de transaction → travail → commit en cas de succès »
Cette méthode continuait à occuper des slots de connexion même sans utiliser réellement la DB, au point qu’il a fallu augmenter le nombre de connexions Postgres à plusieurs milliers
Ils ont donc ajouté dans le code Rust une vérification à la compilation pour que le compilateur avertisse immédiatement si un
.awaitest appelé dans une fonction async alors qu’une connexion est encore détenuePlus de 100 endroits ont été corrigés, mais grâce à cela, les tests de charge ne ralentissent plus avec un pool de 32 connexions au lieu de 10 000
Réduire simplement le délai d’expiration idle est aussi une option, mais la vérification statique s’est révélée une solution bien plus fiable
L’article paraît trop superficiel et se contente de répéter des mots-clés du genre « on a shardé ! »
Il n’y avait presque aucun détail, et cela donnait l’impression de phrases écrites pour le SEO
En résumé, le message de l’article semblait être : « un writer unique ne passe pas à l’échelle, donc on a réduit les écritures et séparé les lectures »
Il n’y avait presque rien de nouveau, seulement des approches classiques comme l’optimisation des requêtes, le sharding et les read replicas
Ce que j’aime dans Postgres, c’est qu’il peut déjà encaisser une assez grande échelle simplement en ajoutant du CPU et du disque
À ce stade, on a aussi les moyens d’embaucher un spécialiste du sharding
Donc dire que « pour faire du sharding, il faut quitter Postgres » semble un peu étrange
Par exemple, OpenAI affiche encore aujourd’hui des pertes massives, et certaines actualités disent même qu’il n’est pas certain que l’entreprise tienne jusqu’en 2027
Concernant les changements de schéma et les timeouts, il serait bien plus efficace de ne pas se limiter aux timeouts
et d’exécuter en parallèle, pendant le déploiement du schéma, des scripts qui terminent automatiquement les transactions en conflit
Ce serait bien que Postgres fournisse cela nativement — mieux vaut annuler certaines transactions que d’attendre sous un verrou lourd
Comme il s’agit du premier article du blog Engineering d’OpenAI, c’était intéressant
J’aimerais voir davantage de retours d’expérience à l’avenir
La configuration de réplication m’intéressait
Ils disent avoir déployé 50 read replicas avec presque aucune latence de réplication,
mais en pratique il est fort probable que certaines réplicas prennent du retard à cause de pics de CPU ou de mémoire
Dans ce cas, le primaire pourrait aussi ralentir à cause de l’attente de transmission du WAL
Il y avait un passage disant que « lorsqu’une nouvelle fonctionnalité nécessite des tables supplémentaires, on la met non pas dans PostgreSQL mais dans Azure CosmosDB »
Cela donnait l’impression qu’ils conservaient le système existant tout en déplaçant uniquement les nouvelles fonctionnalités vers une autre DB
Ils disent avoir augmenté la taille des instances, mais on se demande jusqu’où
Quels CPU et quelle RAM utilisent-ils ? Est-ce la même classe d’instances que pour les clients ordinaires, ou bien du matériel personnalisé ?
Par exemple : Azure Standard_E192ibds_v6 (96 cœurs, 1,8 To de RAM, 10 To de SSD, 3M IOPS)
Il existe encore plus grand, avec pour SAP HANA des modèles comme Standard_M896ixds_24_v3, offrant 896 cœurs, 32 To de mémoire et un réseau à 185 Gbps
Ce type de machine coûte autour de 175 000 dollars par mois, mais OpenAI a probablement obtenu une forte remise
Personnellement, je préfère utiliser pour un serveur DB les VM HPC HX176rs
Grâce au cache HBM, le débit mémoire est bien supérieur, et les performances étaient bien meilleures que celles de VM généralistes de prix comparable
Utiliser Azure PostgreSQL et CosmosDB ensemble doit représenter un coût énorme
Malgré cela, cet article faisait partie des exemples les plus réalistes de « PostgreSQL à l’échelle »
L’approche consistant à opérer dans un environnement cloud standard, sans modifier le kernel ni bricoler le code source, paraissait crédible