Maison > Article > base de données > Introduction détaillée du mécanisme de verrouillage MySQL
1. Niveau d'isolement
(1) Lecture non engagée (RU)
Sous ce niveau d'isolement, les transactions ne sont pas isolées du tout, des lectures sales se produiront et des enregistrements non validés peuvent être lus, qui ne seront pas utilisés dans des situations réelles.
(2) Lire validé (RC)
Seuls les enregistrements validés peuvent être lus. Ce type de sous le niveau d'isolement, il y aura une lecture fantôme. La lecture dite fantôme fait référence au phénomène selon lequel la même requête est exécutée plusieurs fois dans la même transaction et les enregistrements renvoyés ne sont pas exactement les mêmes. La cause première de la lecture fantôme est que sous le niveau d'isolement RC, chaque instruction lira la mise à jour de la transaction soumise. Si d'autres transactions sont soumises entre les deux requêtes, les résultats des deux requêtes seront incohérents. Néanmoins, le niveau d’isolement read-commit est largement utilisé dans les environnements de production.
(3) Lecture répétable (RR)
Le niveau d'isolement de lecture répétable résout le problème de la lecture non répétable, mais le problème de la lecture fantôme n'est toujours pas résolue. Alors, quelle est la différence entre une lecture non répétable et une lecture fantôme ? La lecture non répétable se concentre sur la modification, c'est-à-dire que les valeurs lues deux fois sont différentes ; tandis que la lecture fantôme se concentre sur les modifications du nombre d'enregistrements [insertion et suppression]. Généralement, les manuels nous disent que le problème de lecture fantôme ne peut être résolu que lorsque le niveau d'isolement de sérialisation est atteint, mais le RR innodb de MySQL résout le problème de lecture fantôme, principalement via les verrous GAP. De plus, toutes les bases de données n'implémentent pas ce niveau d'isolement. Plus tard, nous présenterons brièvement comment MySQL implémente le niveau d'isolement de lecture répétable.
(4)Sérialisable
En mode d'isolement de sérialisation, les lectures sales, les fantômes, mais les transactions sont éliminées Le degré de concurrence diminue fortement. Le niveau d'isolement d'une transaction est inversement proportionnel à la simultanéité de la transaction. Plus le niveau d'isolement est élevé, plus la simultanéité de la transaction est faible. Dans un environnement de production réel, l'administrateur de base de données fera un compromis entre la concurrence et la satisfaction des besoins de l'entreprise, et choisira un niveau d'isolement approprié.
2. Méthode de planification simultanée
Une autre chose étroitement liée au niveau d'isolement est la planification simultanée, grâce à laquelle le niveau d'isolement est atteint. Pour la planification simultanée, différents fournisseurs de bases de données ont des mécanismes de mise en œuvre différents, mais les principes de base sont similaires. Ils utilisent tous le verrouillage pour protéger les objets de données contre la modification simultanée de plusieurs transactions. Par rapport au contrôle de concurrence traditionnel basé sur le verrouillage, la principale caractéristique du contrôle de concurrence multiversion (MVCC) est qu'il ne se verrouille pas en lecture. Cette fonctionnalité améliore considérablement la concurrence du système pour les scénarios où il y a beaucoup de lectures et peu d'écritures. donc la plupart des bases de données relationnelles implémentent toutes MVCC.
3. Protocole de verrouillage en deux phases
La signification du protocole de verrouillage en deux phases est que la transaction est divisée en deux phases. La première phase est Après l'obtention du blocus, la deuxième étape consiste à lever le blocus. Le blocage en deux étapes garantit l'exactitude de la planification simultanée. Comparé au verrouillage en une étape (obtention simultanée de tous les verrous requis pour une transaction), le verrouillage en deux phases améliore la concurrence, mais il entraîne également la possibilité d'un blocage.
4. Impasse
La soi-disant impasse fait référence à deux ou plusieurs transactions, chacune occupant les ressources que l'autre partie espère obtenir. , formant un Les boucles d'attente sont dans un état où les unes les autres ne peuvent pas continuer à s'exécuter.
5. Types de verrous
Selon le type de verrou, il peut être divisé en verrou partagé, verrou exclusif, verrou partagé d'intention et intention de verrouillage exclusif. Selon la granularité du verrou, il peut être divisé en verrou de ligne et verrou de table. Pour MySQL, le mécanisme de transaction est davantage implémenté par le moteur de stockage sous-jacent. Par conséquent, le niveau MySQL n'a que des verrous de table, tandis que le moteur de stockage InnODB qui prend en charge les transactions implémente des verrous de ligne (verrous d'enregistrement), des verrous d'espacement et des verrous de clé suivante. . Le verrou d'enregistrement de Mysql est essentiellement le verrou de l'enregistrement d'index, car innodb est une table organisée en index ; le verrou d'espacement est le verrou de l'espace d'enregistrement d'index, qui n'est valide que sous le niveau d'isolation RR ; le verrou d'enregistrement plus l'espace avant la combinaison de verrouillage d'enregistrement. mysql implémente le niveau d'isolation RR via des verrous d'espacement et des verrous de clé suivante.
Remarque :
Pour les opérations de mise à jour (la lecture n'est pas verrouillée), le verrouillage de la liaison montante n'est possible que si l'index est utilisé sinon, le l'index clusterisé sera Un verrou en écriture sur chaque ligne équivaut en fait à un verrou en écriture sur la table.
Si plusieurs enregistrements physiques correspondent au même index, des conflits de verrouillage se produiront également s'ils sont accédés en même temps
Lorsque le La table a plusieurs index À l'heure actuelle, différentes transactions peuvent utiliser différents index pour verrouiller différentes lignes. De plus, innodb utilisera des verrous de ligne pour verrouiller les enregistrements de données (index clusterisé) en même temps.
Dans le cadre du mécanisme de contrôle de concurrence MVCC, aucune opération ne bloquera l'opération de lecture, et l'opération de lecture ne bloquera aucune opération, simplement parce que l'opération de lecture n'est pas verrouillée.
En tant que moteur de stockage open source, RocksDB prend en charge les caractéristiques ACID des transactions. Pour prendre en charge I (Isolation) dans ACID, le contrôle de concurrence est indispensable. Cet article traite principalement de la mise en œuvre du mécanisme de verrouillage de RocksDB, et les détails le seront. Pour l'analyse du code source, j'espère que grâce à cet article, les lecteurs pourront acquérir une compréhension plus approfondie des principes de contrôle de concurrence de RocksDB. L'article commence principalement par les quatre aspects suivants : Tout d'abord, je présenterai la structure de base du verrouillage RocksDB. Ensuite, je présenterai la surcharge de l'espace de verrouillage sous la conception de la structure de données de verrouillage de ligne RocksDB. Ensuite, je présenterai le processus de verrouillage de plusieurs types. scénarios.Enfin, je présenterai le verrou, un mécanisme essentiel de détection de blocage dans le mécanisme.
1. Structure de données de verrouillage de ligne
La granularité minimale du verrouillage de RocksDB est la ligne. la key , chaque clé correspond à une structure LockInfo. Toutes les clés sont gérées via la table de hachage Lorsque vous recherchez un verrou, vous pouvez le localiser directement via la table de hachage pour déterminer si la clé a été verrouillée. Mais s'il n'y a qu'une seule table de hachage globalement, cela provoquera de nombreux conflits lorsque accèdera à cette table de hachage, affectant les performances de concurrence. RocksDB est d'abord divisé par Columnfamily. Les verrous de chaque Columnfamily sont gérés par un LockMap, et chaque LockMap est divisé en plusieurs fragments. Chaque fragment est géré par LockMapStripe et la table de hachage (std::unordered_map2fd0ca67a962f3eb001862b66b94fb78acquire_snapshot(false),延迟获取快照(加锁后,再拿snapshot)
5).再次调用get_for_update,由于此时key已经被加锁,重试一定可以成功。
6).执行更新操作
7).跳转到1,继续执行,直到主键不符合条件时,则结束。
3.3.基于二级索引的更新
这种场景与3.2类似,只不过多一步从二级索引定位主键过程。
1).创建Snapshot,基于迭代器扫描二级索引
2).根据二级索引反向找到主键,实际上也是调用get_row_by_rowid,这个过程就会尝试对key加锁
3).继续根据二级索引遍历下一个主键,尝试加锁
4).当返回的二级索引不符合条件时,则结束
4.死锁检测算法
死锁检测采用DFS((Depth First Search,深度优先算法),基本思路根据加入等待关系,继续查找被等待者的等待关系,如果发现成环,则认为发生了死锁,当然在大并发系统下,锁等待关系非常复杂,为了将死锁检测带来的资源消耗控制在一定范围,可以通过设置deadlock_detect_depth来控制死锁检测搜索的深度,或者在特定业务场景下,认为一定不会发生死锁,则关闭死锁检测,这样在一定程度上有利于系统并发的提升。需要说明的是,如果关闭死锁,最好配套将锁等待超时时间设置较小,避免系统真发生死锁时,事务长时间hang住。死锁检测基本流程如下:
1.定位到具体某个分片,获取mutex
2.调用AcquireLocked尝试加锁
3.若上锁失败,则触发进行死锁检测
4.调用IncrementWaiters增加一个等待者
5.如果等待者不在被等待者map里面,则肯定不会存在死锁,返回
6.对于被等待者,沿着wait_txn_map_向下检查等待关系,看看是否成环
7.若发现成环,则将调用DecrementWaitersImpl将新加入的等待关系解除,并报死锁错误。
相关的数据结构:
class TransactionLockMgr { // Must be held when modifying wait_txn_map_ and rev_wait_txn_map_. std::mutex wait_txn_map_mutex_; // Maps from waitee -> number of waiters. HashMap<TransactionID, int> rev_wait_txn_map_; // Maps from waiter -> waitee. HashMap<TransactionID, autovector<TransactionID>> wait_txn_map_; DecrementWaiters // IncrementWaiters // } struct TransactionOptions { bool deadlock_detect = false; //是否检测死锁 int64_t deadlock_detect_depth = 50; //死锁检测的深度 int64_t lock_timeout = -1; //等待锁时间,线上一般设置为5s int64_t expiration = -1; //持有锁时间, }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!