PostgreSQL scala. Sul serio. Il caso OpenAI lo dimostra a livello planetario.
Il Contesto
OpenAI gestisce ChatGPT — 800 milioni di utenti attivi — con PostgreSQL come database primario. Non un database distribuito custom. Non un sistema NoSQL progettato per la scala. PostgreSQL.
Un singolo nodo primario, oltre 50 read replica su Azure, milioni di query al secondo.
Nessuno sharding.
Un singolo primary PostgreSQL + 50 read replica gestisce milioni di QPS per uno dei servizi più usati al pianeta. Senza sharding. Senza database esotici.
Questo dovrebbe far riflettere chiunque stia valutando di abbandonare PostgreSQL perché "non scala."
L'Architettura
L'approccio di OpenAI è deceptively simple:
| Componente | Dettaglio |
|---|---|
| Primary | Singolo nodo Azure PostgreSQL Flexible Server |
| Read Replica | 50+ replica distribuite geograficamente |
| Connection Pooling | PgBouncer davanti a ogni istanza |
| Sharding | Nessuno |
| Latenza media | < 5ms (dopo ottimizzazioni) |
Prima e dopo PgBouncer
La latenza è passata da ~50ms a meno di 5ms semplicemente introducendo connection pooling con PgBouncer. Non un rewrite architetturale. Non un cambio di database. Un proxy layer.
Se non hai PgBouncer (o equivalente) davanti al tuo PostgreSQL in produzione, stai lasciando performance gratuite sul tavolo. È il singolo cambiamento con il miglior rapporto costo/beneficio in qualsiasi deployment PostgreSQL.
Il Vero Bottleneck: Le Scritture
Le letture scalano orizzontalmente con le replica. Aggiungi nodi, distribuisci il carico. Problema risolto.
Le scritture no. Tutto passa dal primary. Questa è fisica, non un bug.
Strategie di OpenAI per le scritture
Eliminare scritture non necessarie
Prima di ottimizzare, hanno rimosso. Scritture applicative che non servivano, log che potevano andare altrove, update che potevano essere lazy.
La migliore ottimizzazione è non fare il lavoro.
Lazy writes con backfill controllato
Invece di scrivere sincrono, hanno implementato scritture differite con backfill a rate controllato. Questo elimina gli spike di traffico in scrittura che causano i problemi peggiori.
Offload dei workload write-heavy
I workload con natural sharding key che generavano volumi estremi di scritture sono stati migrati su sistemi dedicati. PostgreSQL per il core, sistemi specializzati per l'eccezione.
Rate limiting multi-livello
Rate limiting a livello di applicazione, connessione e query digest. Non un singolo punto di controllo, ma una difesa in profondità contro il resource exhaustion.
Considerazioni Architetturali
Perché non sharding?
Lo sharding introduce complessità operativa enorme: query cross-shard, transazioni distribuite, ribilanciamento, routing layer. OpenAI ha dimostrato che con le giuste ottimizzazioni, un singolo primary può gestire carichi che la maggior parte degli engineer considererebbe impossibili.
- Complessità operativa alta
- Query cross-shard costose
- Transazioni distribuite fragili
- Ribilanciamento non banale
- Operativamente semplice
- Tutte le query su un nodo
- Transazioni ACID native
- Scale-up + read replica
Lo sharding ha senso quando le scritture superano la capacità di un singolo nodo. Ma quel momento arriva molto più tardi di quanto pensi — e OpenAI ne è la prova.
MVCC: Il prezzo della concorrenza
PostgreSQL usa Multi-Version Concurrency Control. Ogni update crea una nuova versione della riga. Questo significa:
- Table bloat: righe morte che occupano spazio
- Index bloat: indici che puntano a righe obsolete
- Autovacuum complesso: il garbage collector va tuned con cura
- WAL crescente: più replica = più WAL = più banda di rete
Il tuning dell'autovacuum è una delle attività più sottovalutate nella gestione di PostgreSQL. I default sono conservativi. A scale, vanno rivisti aggressivamente.
Read Replica: Non sono tutte uguali
Un pattern cruciale adottato da OpenAI: segregazione del traffico per priorità.
Non tutte le query sono create uguali. Un utente che aspetta una risposta in real-time ha priorità diversa da un job di analytics.
| Tipo | Replica dedicate | Caratteristiche |
|---|---|---|
| High-priority | Replica dedicate | Latenza minima, nessuna interferenza |
| Low-priority | Replica condivise | Analytics, batch job, report |
| Long-running | Replica isolate | Query > 1s spostate qui |
Questo impedisce che una query di analytics da 30 secondi blocchi le letture real-time. Semplice, ma troppi team mettono tutto sulle stesse replica.
Schema Migration: Il Campo Minato
Le migration in produzione su database ad alto traffico sono dove le cose esplodono. L'approccio di OpenAI:
- Solo operazioni lightweight: niente full table rewrite in produzione
- Timeout DDL a 5 secondi: se non completa in 5s, abort
- Index sempre
CONCURRENTLY: mai bloccare le letture per un index build - Query lente spostate su replica: le query > 1s vengono migrate per non bloccare le migration
ALTER TABLE ... ADD COLUMN ... DEFAULT ... con riscrittura della tabella su un database con milioni di righe è un incidente garantito. Sempre ADD COLUMN nullable, poi backfill separato.
Incidenti e Lezioni
Il cascade failure da Redis
Un'interruzione di Redis ha causato un collapse a cascata dell'intero sistema. Non PostgreSQL il colpevole, ma la dipendenza non gestita.
Lezione: ogni dipendenza esterna è un single point of failure se non hai circuit breaker e fallback.
Il bug WALSender
Un bug dove alta CPU ha triggerato uno spin-loop nel WALSender, impedendo la trasmissione WAL alle replica. Il lag è persistito anche dopo la normalizzazione della CPU.
Lezione: il monitoring della replication lag non è opzionale. E serve alerting su anomalie, non solo su threshold.
Cosa Manca a PostgreSQL (secondo OpenAI)
Queste sono feature request reali che OpenAI ha portato alla community PostgreSQL:
- Index disabling: poter marcare un indice come invalido senza dropparlo, monitorare l'impatto, poi decidere
- Latency percentiles: P95/P99 nativi in
pg_stat_statements, non solo medie - DDL history tracking: uno storico delle modifiche schema accessibile via query
- Wait event semantics: sessioni "active" con wait event "ClientRead" per ore — semantica confusa
- Heuristic defaults: parametri auto-tuned basati su CPU/RAM/disco rilevati
Queste non sono lamentele. Sono feedback concreto da chi opera PostgreSQL a una scala che pochi raggiungono. Se lavori sull'ecosistema PostgreSQL, queste sono le aree dove il contributo ha il massimo impatto.
Le Mie Considerazioni
PostgreSQL è sufficiente. Quasi sempre.
Il caso OpenAI demolisce l'argomento "PostgreSQL non scala". Se scala per 800 milioni di utenti ChatGPT, scala per il tuo progetto. Il problema non è mai PostgreSQL — è come lo usi.
"La tecnologia migliore è la tecnologia noiosa. PostgreSQL è gloriosamente noioso. Ed è per questo che funziona."
La complessità è una scelta, non un requisito
OpenAI avrebbe potuto scegliere un database distribuito custom. Avrebbe potuto fare sharding dal giorno uno. Invece hanno scelto l'approccio più semplice che potesse funzionare e hanno ottimizzato da lì.
Questo è engineering. Non la tecnologia più nuova, ma la soluzione più semplice che risolve il problema.
Connection pooling non è opzionale
Se c'è una singola cosa da portarsi a casa da questo articolo: PgBouncer in produzione. Sempre. La differenza tra 50ms e 5ms non è un'ottimizzazione — è un cambio di categoria.
Il monitoring decide tutto
OpenAI ha avuto un solo incidente Sev0 attribuibile a PostgreSQL in nove mesi. Non perché PostgreSQL sia magico, ma perché hanno investito in observability: replication lag, query performance, connection states, WAL volume.
Non puoi ottimizzare quello che non misuri.
Lo sharding è l'ultima risorsa
Troppe architetture partono con sharding "per sicurezza". OpenAI dimostra che il costo della complessità operativa dello sharding supera quasi sempre il beneficio, fino a scale che il 99.99% dei progetti non raggiungerà mai.
- PostgreSQL scala verticalmente molto più di quanto pensi
- Read replica sono economiche e lineari
- PgBouncer è un moltiplicatore di performance gratuito
- L'ecosistema di monitoring è maturo
- ACID compliance nativa senza compromessi
- Write scaling rimane il vero limite
- MVCC richiede tuning attivo dell'autovacuum
- Replication lag cresce con il numero di replica
- Schema migration su tabelle grandi resta rischioso
- Mancano feature di observability native (P95/P99)
Takeaway Operativi
Per chi sta scalando PostgreSQL oggi:
| Priorità | Azione | Impatto |
|---|---|---|
| 1 | Introdurre PgBouncer | Riduzione latenza 10x |
| 2 | Segregare traffico su replica dedicate | Eliminare interferenza tra workload |
| 3 | Tuning aggressivo autovacuum | Prevenire bloat e degradazione |
| 4 | Timeout su DDL e query | Prevenire lock chain |
| 5 | Monitoring replication lag e WAL | Early warning su degradazione |
| 6 | Lazy writes per spike control | Smooth del traffico in scrittura |
| 7 | Sharding solo quando tutto il resto non basta | Complessità come ultima risorsa |