Heim  >  Artikel  >  Datenbank  >  Detaillierte Einführung des MySQL-Sperrmechanismus

Detaillierte Einführung des MySQL-Sperrmechanismus

零下一度
零下一度Original
2017-07-17 10:01:341768Durchsuche

1. Isolationsstufe

(1) Read Uncommitted (RU)

Unter dieser Isolationsstufe sind Transaktionen überhaupt nicht isoliert, es kommt zu Dirty Reads und es können nicht festgeschriebene Datensätze gelesen werden, die in tatsächlichen Situationen nicht verwendet werden.

(2) Read commit (RC)

Nur ​​festgeschriebene Datensätze können unter der Isolationsstufe gelesen werden. Es kommt zu Phantomlesungen. Die sogenannten Phantomlesungen beziehen sich auf das Phänomen, dass dieselbe Abfrage mehrmals in derselben Transaktion ausgeführt wird und die zurückgegebenen Datensätze nicht genau gleich sind. Die Hauptursache für das Phantomlesen liegt darin, dass unter der RC-Isolationsstufe jede Anweisung die Aktualisierung der übermittelten Transaktion liest. Wenn zwischen den beiden Abfragen andere Transaktionen übermittelt werden, sind die Ergebnisse der beiden Abfragen inkonsistent. Dennoch wird die Read-Commit-Isolationsstufe häufig in Produktionsumgebungen verwendet.

(3) Wiederholbares Lesen (RR)

Die Isolationsstufe für wiederholbares Lesen löst das Problem des nicht wiederholbaren Lesens, aber das Problem von Phantomlesung ist immer noch nicht gelöst. Was ist also der Unterschied zwischen nicht wiederholbarem Lesen und Phantomlesen? Das nicht wiederholbare Lesen konzentriert sich auf Änderungen, das heißt, die zweimal gelesenen Werte sind unterschiedlich, während sich das Phantomlesen auf Änderungen in der Anzahl der Datensätze [Einfügung und Löschung] konzentriert. Im Allgemeinen sagen uns Lehrbücher, dass das Phantom-Lese-Problem nur gelöst werden kann, wenn die Serialisierungsisolationsstufe erreicht ist, aber MySQLs innodb ist etwas Besonderes, das das Phantom-Lese-Problem hauptsächlich durch GAP-Sperren löst. Darüber hinaus implementieren nicht alle Datenbanken diese Isolationsstufe. Später werden wir kurz vorstellen, wie MySQL die wiederholbare Leseisolationsstufe implementiert.

(4)Serialisierbar

Im Serialisierungsisolationsmodus werden Dirty Reads, Phantome, aber Transaktionen eliminiert. Der Grad der Parallelität sinkt stark Der Isolationsgrad einer Transaktion ist umgekehrt proportional zur Parallelität der Transaktion. Je höher der Isolationsgrad, desto geringer ist die Parallelität der Transaktion. In einer tatsächlichen Produktionsumgebung wird der DBA einen Kompromiss zwischen Parallelität und der Erfüllung von Geschäftsanforderungen eingehen und eine geeignete Isolationsstufe wählen.

2. Gleichzeitige Planungsmethode

Eine weitere Sache, die eng mit der Isolationsstufe zusammenhängt, ist die gleichzeitige Planung, durch die die Isolationsstufe erreicht wird. Für die gleichzeitige Planung verfügen verschiedene Datenbankanbieter über unterschiedliche Implementierungsmechanismen, die Grundprinzipien sind jedoch ähnlich. Sie verwenden alle Sperren, um Datenobjekte vor der gleichzeitigen Änderung durch mehrere Transaktionen zu schützen. Im Vergleich zur herkömmlichen sperrenbasierten Parallelitätskontrolle besteht das Hauptmerkmal der Mehrversions-Parallelitätskontrolle (MVCC) darin, dass sie nicht zum Lesen gesperrt wird. Diese Funktion verbessert die Parallelität des Systems in Szenarien mit vielen Lesevorgängen und wenigen Schreibvorgängen erheblich. Daher implementieren die meisten relationalen Datenbanken alle MVCC.

3. Zwei-Phasen-Sperrprotokoll

Die Bedeutung des Zwei-Phasen-Sperrprotokolls besteht darin, dass die Transaktion in zwei Phasen unterteilt ist. Die erste Phase besteht darin, die Blockade nach Erhalt der Blockade aufzuheben. Die zweistufige Blockierung stellt die Korrektheit der gleichzeitigen Planung sicher. Im Vergleich zum einstufigen Sperren (das gleichzeitige Erhalten aller für eine Transaktion erforderlichen Sperren) verbessert das zweiphasige Sperren die Parallelität, birgt aber auch die Möglichkeit eines Deadlocks.

4. Deadlock

Der sogenannte Deadlock bezieht sich auf zwei oder mehr Transaktionen, von denen jede die Ressourcen belegt, die die andere Partei zu erhalten erwartet Die Warteschleifen befinden sich in einem Zustand, in dem sie sich gegenseitig nicht mehr ausführen können.

5. Sperrtypen

Je nach Art der Sperre kann sie in gemeinsame Sperre, exklusive Sperre, beabsichtigte gemeinsame Sperre usw. unterteilt werden Absicht exklusive Sperre. Entsprechend der Granularität der Sperre kann sie in Zeilensperre und Tabellensperre unterteilt werden. Bei MySQL wird der Transaktionsmechanismus eher von der zugrunde liegenden Speicher-Engine implementiert. Daher verfügt die MySQL-Ebene nur über Tabellensperren, während die Innodb-Speicher-Engine, die Transaktionen unterstützt, Zeilensperren (Datensatzsperren), Lückensperren und Sperren für den nächsten Schlüssel implementiert. . Die Datensatzsperre von MySQL ist im Wesentlichen die Sperre des Indexdatensatzes, da Innodb eine indexorganisierte Tabelle ist; die Lückensperre ist die Sperre der Indexdatensatzlücke, die nur unter der RR-Isolationsstufe gültig ist die Datensatzsperre plus die Lücke vor der Datensatzsperrenkombination. MySQL implementiert die RR-Isolationsstufe durch Lückensperren und Next-Key-Sperren.

Hinweis:

Für Aktualisierungsvorgänge (Lesen ist nicht gesperrt) ist die Uplink-Sperre nur möglich, wenn der Index verwendet wird Clustered-Index wird sein Eine Schreibsperre für jede Zeile entspricht tatsächlich einer Schreibsperre für die Tabelle.

Wenn mehrere physische Datensätze demselben Index entsprechen, kommt es auch zu Sperrkonflikten, wenn auf sie gleichzeitig zugegriffen wird.

Wenn die Die Tabelle verfügt über mehrere Indizes. Zu diesem Zeitpunkt können verschiedene Transaktionen unterschiedliche Indizes verwenden, um verschiedene Zeilen zu sperren. Darüber hinaus verwendet innodb gleichzeitig Zeilensperren, um die Datensätze (Clustered-Index) zu sperren.

Unter dem MVCC-Parallelitätskontrollmechanismus blockiert keine Operation die Leseoperation, und die Leseoperation blockiert keine Operation, nur weil die Leseoperation nicht gesperrt ist.

 

Als Open-Source-Speicher-Engine unterstützt RocksDB die ACID-Eigenschaften von Transaktionen. Um I (Isolation) in ACID zu unterstützen, ist die Parallelitätskontrolle unerlässlich Ich hoffe, dass die Leser durch diesen Artikel ein tieferes Verständnis der Prinzipien der RocksDB-Parallelitätskontrolle erlangen können. Der Artikel beginnt hauptsächlich mit den folgenden vier Aspekten. Zuerst werde ich die Grundstruktur der RocksDB-Sperre vorstellen. Anschließend werde ich den Sperrraum-Overhead im Rahmen des Designs der RocksDB-Zeilensperrdatenstruktur vorstellen Abschließend werde ich die Sperre vorstellen, einen wesentlichen Mechanismus zur Erkennung von Deadlocks.

1. Zeilensperrdatenstruktur
Die minimale Sperrgranularität von RocksDB ist Zeile der Schlüssel, jeder Schlüssel entspricht einer LockInfo-Struktur. Alle Schlüssel werden über die Hash-Tabelle verwaltet. Wenn Sie nach einer Sperre suchen, können Sie diese direkt über die Hash-Tabelle finden, um festzustellen, ob der Schlüssel gesperrt wurde. Wenn es jedoch global nur eine Hash-Tabelle gibt, kommt es zu vielen Konflikten, wenn auf diese Hash-Tabelle zugreift, was sich auf die Parallelitätsleistung auswirkt. RocksDB wird zunächst nach Columnfamily aufgeteilt. Die Sperren in jeder Columnfamily werden von einer LockMap verwaltet, und jede LockMap wird in mehrere Shards aufgeteilt. Jeder Shard wird von LockMapStripe verwaltet, und die Hash-Tabelle (std::unordered_map46dcd34d039260f738c46b86900277e0acquire_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; //持有锁时间,
}

Das obige ist der detaillierte Inhalt vonDetaillierte Einführung des MySQL-Sperrmechanismus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn