Concurrence : transactions, verrous, SKIP LOCKED
MVCC : pourquoi les lecteurs ne bloquent pas les écrivains
Postgres utilise le MVCC (Multi-Version Concurrency Control) : chaque transaction voit un instantanĂ© cohĂ©rent de la base. Une Ă©criture crĂ©e une nouvelle version de la ligne sans dĂ©truire l'ancienne â les lecteurs continuent de voir leur version. ConsĂ©quence pratique : les lectures ne bloquent jamais les Ă©critures et inversement. Les conflits n'arrivent qu'entre Ă©crivains sur la mĂȘme ligne.
Corollaire opĂ©rationnel : les versions mortes s'accumulent â VACUUM (auto en gĂ©nĂ©ral) les recycle. Une table trĂšs Ă©crite mal vacuumĂ©e « gonfle » (bloat) â un classique de prod Ă connaĂźtre.
Les niveaux d'isolation (ce qu'ils garantissent)
- Read Committed (dĂ©faut) : chaque requĂȘte voit ce qui est committĂ© Ă son dĂ©marrage â suffisant pour 95 % des cas ;
- Repeatable Read : l'instantanĂ© est figĂ© pour toute la transaction (utile pour un rapport cohĂ©rent multi-requĂȘtes) ;
- Serializable : comme si les transactions s'exĂ©cutaient en sĂ©rie â la base dĂ©tecte les anomalies et fait Ă©chouer une transaction (Ă toi de la rejouer). Le prix de la garantie maximale.
La rĂšgle : rester en Read Committed, monter d'un cran seulement quand une anomalie prĂ©cise le justifie â et savoir gĂ©rer le serialization_failure (retry) si tu montes Ă Serializable.
Les verrous applicatifs et le pattern file d'attente
Le cours Stack IA a montrĂ© FOR UPDATE SKIP LOCKED pour le polling email et le reconciler de jobs â voici le pourquoi :
-- N workers se partagent une file, sans coordinateur externe :
SELECT * FROM jobs WHERE status = 'pending'
ORDER BY created_at
FOR UPDATE SKIP LOCKED -- verrouille MES lignes, SAUTE celles des autres
LIMIT 10;
-- ⊠traiter ⊠UPDATE status = 'done' ⊠COMMIT (libÚre les verrous)
FOR UPDATE: verrouille les lignes lues (les autres transactions attendent) ;SKIP LOCKED: au lieu d'attendre, saute les lignes dĂ©jĂ verrouillĂ©es â chaque worker prend un lot disjoint, zĂ©ro contention. C'est ce qui transforme une table en file d'attente concurrente sans Redis ni RabbitMQ ;NOWAIT: variante qui Ă©choue immĂ©diatement au lieu de sauter (quand tu veux savoir que c'est verrouillĂ©).
Et les advisory locks (pg_advisory_lock) pour un verrou applicatif nommĂ© (« un seul worker exĂ©cute cette tĂąche cron ») â un mutex distribuĂ© gratuit.
GrĂące au MVCC, en PostgresâŠ