Comment les bases de données gèrent les transactions simultanées sans corrompre les données
Le contrôle de concurrence est l'ensemble des mécanismes qu'un système de gestion de base de données (SGBD) utilise pour gérer les transactions simultanées sans corrompre les données. Lorsque plusieurs utilisateurs ou processus lisent et écrivent en même temps, un accès non contrôlé entraîne des anomalies de données, telles que des mises à jour perdues, des lectures sales et des résultats incohérents qui peuvent se propager aux systèmes en aval.
Le contrôle de concurrence applique le « I » (Isolation) des transactions ACID : les transactions concurrentes doivent produire le même résultat que si elles s'exécutaient les unes après les autres, une propriété connue sous le nom de sérialisabilité. Sans cela, une application bancaire pourrait perdre des virements, un système de gestion des stocks pourrait vendre des produits en surstock et un pipeline d'analyse pourrait produire des rapports basés sur des données partiellement écrites.
Ce guide couvre les problèmes fondamentaux de concurrence, les principaux mécanismes pour les résoudre — verrouillage, contrôle de concurrence multi-version (MVCC) et stratégies optimistes et pessimistes — ainsi que les niveaux d'isolation, la gestion des interblocages et des conseils pratiques pour choisir l'approche adaptée à votre charge de travail.
Les systèmes de bases de données modernes gèrent couramment des milliers à des millions de transactions concurrentes par seconde. Chaque fois qu'un utilisateur soumet une requête, met à jour un enregistrement ou lance un pipeline ETL, le SGBD doit coordonner cette opération avec toutes les autres opérations en cours au même moment. Sans contrôle de concurrence, les transactions entrelacées produisent des résultats imprévisibles et incorrects.
Considérez un scénario concret : deux utilisateurs mettent à jour le solde du même compte bancaire simultanément. L'utilisateur A lit le solde (1 000 $), soustrait 200 $ et écrit 800 $. L'utilisateur B lit également 1 000 $, ajoute 500 $ et écrit 1 500 $. Le résultat correct dépend de l'ordre — soit 800 $ soit 1 500 $ — mais sans coordination, une écriture écrase simplement l'autre. C'est un cas classique de mise à jour perdue, l'une des plusieurs anomalies que le contrôle de concurrence vise à prévenir.
Le contrôle de concurrence applique la sérialisabilité : le résultat d'une exécution concurrente doit correspondre à un certain ordre sériel des mêmes transactions. Cela prend directement en charge les quatre garanties ACID — atomicité (tout ou rien), cohérence (transitions d'état valides), isolation (pas d'interférence) et durabilité (les modifications validées sont permanentes). Cela garantit la base sur laquelle chaque application fonde la confiance dans ses données.
Avant d'explorer les solutions, il est utile de comprendre les anomalies spécifiques qui surviennent lorsque des transactions concurrentes s'exécutent sans contrôles appropriés.
Ces quatre anomalies expliquent l'existence de chaque mécanisme de contrôle de concurrence. Chaque mécanisme en empêche certaines ou toutes, en fonction du niveau d'isolation qu'il applique.
Le verrouillage est l'approche la plus ancienne et la plus intuitive du contrôle de concurrence. Le SGBD attribue des verrous aux éléments de données — lignes, pages ou tables entières — avant d'autoriser les transactions à y accéder. Un verrou agit comme un gardien : si une autre transaction détient déjà un verrou conflictuel, la transaction demandeuse doit attendre.
La granularité des verrous introduit un compromis important. Les verrous au niveau de la ligne maximisent la concurrence car les lignes non liées restent accessibles, mais ils ajoutent une surcharge car le système doit suivre de nombreux verrous individuels. Les verrous au niveau de la table sont plus simples et moins coûteux à gérer, mais obligent les transactions non liées à attendre, ce qui réduit le débit.
Le verrouillage en deux phases est le protocole standard pour garantir la sérialisabilité par le biais de verrous. Il divise chaque transaction en deux phases. Pendant la phase de croissance, une transaction acquiert tous les verrous dont elle a besoin mais n'en relâche jamais. Une fois qu'elle relâche son premier verrou, elle entre dans la phase de décroissance et ne peut que relâcher des verrous, jamais en acquérir de nouveaux. Cette règle garantit que l'ordre dans lequel les transactions verrouillent les éléments de données est cohérent, ce qui garantit à son tour un ordonnancement sérialisable.
Le 2PL strict est une variante courante qui conserve tous les verrous jusqu'à ce que la transaction soit validée. Cela empêche les annulations en cascade, une situation où une transaction annulée oblige d'autres transactions qui ont lu ses données non validées à être également annulées. La plupart des bases de données relationnelles qui utilisent le contrôle de concurrence basé sur le verrouillage implémentent une forme de 2PL strict.
L'inconvénient du 2PL est qu'il introduit des blocages — les transactions doivent attendre les verrous détenus par d'autres — et crée les conditions des interblocages.
MVCC adopte une approche fondamentalement différente : au lieu de bloquer l'accès, il maintient plusieurs versions de chaque élément de données afin que chaque transaction voie un instantané cohérent de la base de données. Lorsqu'une transaction écrit une ligne, MVCC crée une nouvelle version au lieu d'écraser celle existante. Les lecteurs continuent de voir la version qui était actuelle au moment où leur transaction a commencé.
L'avantage principal est que les lecteurs ne bloquent jamais les écrivains et les écrivains ne bloquent jamais les lecteurs. C'est un avantage de performance majeur pour les charges de travail à forte lecture, c'est pourquoi MVCC est le mécanisme de contrôle de concurrence dominant dans les bases de données modernes. PostgreSQL, MySQL/InnoDB, Oracle et la plupart des systèmes OLTP et OLAP contemporains utilisent une forme de MVCC.
Les conflits d'écriture sont détectés au moment de la validation. Si deux transactions modifient la même ligne, la première à valider gagne et la seconde doit réessayer. Cette approche optimiste de la résolution des conflits d'écriture maintient un débit élevé lorsque les conflits sont rares, ce qui est généralement le cas.
L'isolation par instantané est le niveau d'isolation le plus courant basé sur MVCC. Chaque transaction voit la base de données telle qu'elle existait au moment où la transaction a commencé, empêchant les lectures sales et les lectures non répétables. Cependant, l'isolation par instantané permet une anomalie subtile appelée dérive d'écriture, où deux transactions lisent des données qui se chevauchent, puis effectuent des écritures basées sur ce qu'elles ont lu, résultant en un état qu'aucune des deux transactions n'aurait produit seule. L'isolation par instantané sérialisable (SSI) comble cette lacune au prix d'une surcharge supplémentaire.
MVCC introduit ses propres compromis. La maintenance de plusieurs versions consomme du stockage supplémentaire, et le système doit périodiquement nettoyer les versions obsolètes — un processus connu sous le nom de VACUUM dans PostgreSQL. En cas de forte contention d'écriture, le coût de réessai et la surcharge de gestion des versions peuvent devenir importants.
Au-delà des mécanismes spécifiques de verrouillage et de MVCC, les stratégies de contrôle de concurrence se répartissent en deux camps philosophiques : pessimiste et optimiste. Comprendre quel camp convient à votre charge de travail est l'une des décisions architecturales les plus importantes qu'une équipe de données puisse prendre.
Le contrôle de concurrence pessimiste suppose que les conflits sont probables et les empêche en acquérant des verrous avant d'accéder aux données. Cette approche est préférable pour les charges de travail à forte écriture où les conflits sont fréquents et le coût d'annulation et de réessai d'une transaction est élevé. Les systèmes de grand livre financier, où chaque écriture doit être séquencée et vérifiée, en sont un cas d'utilisation classique.
L'inconvénient est le blocage. En cas de forte concurrence, les transactions se mettent en file d'attente en attendant les verrous, ce qui réduit le débit. Dans le pire des cas, les demandes de verrouillage concurrentes créent des interblocages.
Le contrôle de concurrence optimiste suppose que les conflits sont rares. Les transactions s'exécutent librement sans acquérir de verrous, en opérant sur leurs propres copies privées des données. Au moment de la validation, le système vérifie si les lectures et écritures de la transaction entrent en conflit avec une autre transaction validée. Si aucun conflit n'est détecté, la transaction est validée. Si un conflit est détecté, la transaction est annulée et réessayée.
Ce modèle en trois phases — lecture, validation, écriture — excelle dans les environnements où la plupart des transactions ne touchent pas aux mêmes données. Les systèmes de gestion de contenu, les applications de navigation de catalogue et les tableaux de bord de reporting en sont des exemples typiques.
Le revers de la médaille est le travail perdu. Lorsque les conflits sont fréquents, les transactions exécutent de manière répétée leur logique complète pour être ensuite annulées lors de la validation, consommant des ressources sans produire de résultats.
Le choix entre le contrôle pessimiste et optimiste dépend des caractéristiques de la charge de travail. Une contention d'écriture élevée, des transactions courtes et une faible tolérance aux nouvelles tentatives orientent vers le contrôle pessimiste. Les charges de travail à forte dominante de lecture avec une faible probabilité de conflit et des exigences de concurrence élevées favorisent les approches optimistes ou basées sur MVCC.
En pratique, de nombreux systèmes de production combinent les deux stratégies. Un modèle courant utilise MVCC pour les lectures et écritures générales tout en appliquant des verrous pessimistes sur des lignes connues comme points chauds — par exemple, en utilisant SELECT ... FOR UPDATE pour verrouiller une ligne spécifique pour laquelle plusieurs transactions sont susceptibles de se disputer simultanément.
Les niveaux d'isolation définissent les anomalies de concurrence qu'une transaction peut rencontrer. Des niveaux plus stricts empêchent plus d'anomalies mais réduisent la concurrence. La norme SQL définit quatre niveaux, et la plupart des bases de données en implémentent une variante.
| Niveau d'isolation | Lectures non validées (Dirty reads) | Lectures non répétables (Non-repeatable reads) | Lectures fantômes (Phantom reads) | Cas d'utilisation typique |
|---|---|---|---|---|
| Lecture non validée (Read Uncommitted) | Possible | Possible | Possible | Rarement utilisé en production |
| Lecture validée (Read Committed) | Empêché | Possible | Possible | Par défaut dans PostgreSQL, Oracle |
| Lecture répétable (Repeatable Read) | Empêché | Empêché | Possible | Par défaut dans MySQL/InnoDB |
| Sérialisable (Serializable) | Empêché | Empêché | Empêché | Financier, conformité, sécurité critique |
La plupart des applications fonctionnent en toute sécurité au niveau Lecture validée (Read Committed) ou Lecture répétable (Repeatable Read). Choisir Sérialisable (Serializable) est un compromis délibéré qui doit être motivé par des exigences métier spécifiques plutôt qu'utilisé par défaut.
Un interblocage se produit lorsque deux transactions ou plus détiennent chacune des verrous dont l'autre a besoin, créant un cycle d'attente mutuelle. Aucune des deux transactions ne peut progresser et, sans intervention, les deux attendraient indéfiniment.
Conseils pratiques pour minimiser les interblocages : gardez les transactions aussi courtes que possible, accédez aux ressources dans un ordre prévisible, définissez des valeurs de délai d'attente de verrouillage appropriées et surveillez la fréquence des interblocages comme indicateur de santé du système.
Il n'y a pas de réponse universelle. Le mécanisme approprié dépend des caractéristiques de la charge de travail, des exigences de cohérence et des compromis opérationnels. Plusieurs facteurs guident la décision.
De nombreux systèmes de production combinent des stratégies : MVCC par défaut, verrous pessimistes sur les lignes connues comme points chauds et logique de nouvelle tentative au niveau de l'application pour la résolution des conflits optimistes.
Les bases de données distribuées sont confrontées à des défis de coordination supplémentaires. La latence réseau entre les nœuds, la nécessité de tolérance aux pannes et les exigences de consensus augmentent le coût et la complexité du contrôle de concurrence. Les approches incluent le 2PL distribué, le MVCC distribué avec des horodatages globaux — comme utilisé dans le système TrueTime de Google Spanner — et des protocoles de consensus comme Raft et Paxos.
Les plateformes analytiques et lakehouse gèrent la concurrence différemment des bases de données OLTP traditionnelles. Ces systèmes sont optimisés pour les charges de travail à forte dominante de lecture et de scan de grande taille avec isolation par instantané plutôt que pour les modèles de verrouillage au niveau des lignes courants dans les systèmes transactionnels.
Databricks et Delta Lake utilisent le contrôle de concurrence optimiste pour les écritures concurrentes sur la même table. Les écritures suivent un processus en trois étapes : lire la dernière version de la table pour identifier les fichiers affectés, écrire de nouveaux fichiers de données, puis valider au moment de l'engagement qu'aucun changement conflictuel ne s'est produit. Si les transactions ne sont pas en conflit, elles réussissent. Si un conflit est détecté, une nouvelle tentative automatique ou une résolution de conflit s'en charge. Delta Lake implémente un modèle MVCC sans verrouillage, de sorte que les lecteurs voient toujours un instantané cohérent pendant que les écrivains progressent indépendamment.
Les transactions ACID sur les tables Delta Lake garantissent la cohérence des données même lorsque plusieurs pipelines, utilisateurs et requêtes accèdent simultanément aux mêmes données. Pour un examen détaillé de la façon dont la concurrence au niveau des lignes fonctionne en pratique, le blog d'ingénierie de Databricks propose une analyse approfondie des mécanismes sous-jacents.
Cette approche étend les garanties de concurrence au-delà de l'OLTP traditionnel aux charges de travail d'ingénierie de données, ETL et ML où plusieurs écrivains et lecteurs opèrent sur des ensembles de données partagés. En combinant le contrôle de concurrence optimiste, l'isolation par instantané et la résolution automatique des conflits, les plateformes lakehouse modernes apportent la fiabilité des transactions de niveau base de données à l'échelle et à la flexibilité des lacs de données cloud.
Comprendre la théorie du contrôle de concurrence est un défi. L'implémenter de manière fiable sur des données distribuées, plusieurs écrivains et des charges de travail diverses en est un autre. Les équipes qui gèrent leurs propres stratégies de concurrence consacrent un temps d'ingénierie considérable à la configuration des niveaux d'isolation, à l'ajustement du comportement des verrous et à la création de logique de nouvelle tentative — un temps qui ne fait pas avancer leur travail réel.
Databricks Lakebase élimine cette charge opérationnelle. Construit sur la plateforme Databricks Data Intelligence Platform, Lakebase est une base de données entièrement gérée et native dans le cloud qui apporte la fiabilité transactionnelle au lakehouse sans obliger les équipes à implémenter ou configurer elles-mêmes le contrôle de concurrence. Prête à l'emploi, elle offre un contrôle de concurrence optimiste, une isolation par instantané pour les lectures et une isolation sérialisable en écriture pour les écritures — les mêmes mécanismes que cet article couvre, appliqués automatiquement.
Parce que Lakebase utilise le contrôle de concurrence optimiste sur Delta Lake, il n'y a pas de verrous à gérer et pas d'interblocages à déboguer. Les écritures concurrentes suivent le modèle lire-valider-confirmer décrit précédemment dans ce guide : chaque transaction lit la dernière version de la table, écrit de nouveaux fichiers de données et valide au moment de la confirmation qu'aucun changement conflictuel ne s'est produit. Lorsque plusieurs pipelines, utilisateurs ou requêtes écrivent sur la même table, la détection de conflit au niveau des lignes de Delta Lake résout automatiquement les changements non chevauchants — même pour les opérations MERGE, UPDATE et DELETE concurrentes. Les lecteurs voient toujours un instantané cohérent, non affecté par les écritures en cours.
Cela ne se limite pas aux charges de travail analytiques. Lakebase étend les garanties transactionnelles aux charges de travail opérationnelles, à l'ingénierie des données, aux pipelines ETL et au ML — le tout sur la même plateforme. Au lieu de maintenir une base de données OLTP distincte à côté d'un lakehouse et de les relier avec du code d'intégration personnalisé, les équipes exécutent tout via une architecture unique et gouvernée. Les données restent dans des formats ouverts sur un stockage cloud peu coûteux, avec la couche de calcul transactionnelle fonctionnant indépendamment au-dessus.
Le résultat : tous les concepts de contrôle de concurrence abordés dans cet article — MVCC, validation optimiste, isolation des instantanés, résolution des conflits — fonctionnent par défaut sur Databricks. Les équipes peuvent se concentrer sur leurs données et leurs charges de travail, pas sur leur stratégie de concurrence. Explorer Lakebase pour voir comment cela fonctionne en pratique.
(Cet article de blog a été traduit à l'aide d'outils basés sur l'intelligence artificielle) Article original
Abonnez-vous à notre blog et recevez les derniers articles directement dans votre boîte mail.