>  기사  >  데이터 베이스  >  MySQL 잠금 메커니즘에 대한 자세한 소개

MySQL 잠금 메커니즘에 대한 자세한 소개

零下一度
零下一度원래의
2017-07-17 10:01:341796검색

1. 격리 수준

(1) 커밋되지 않은 읽기(RU)

이 격리 수준에서는 트랜잭션이 전혀 격리되지 않고 더티 읽기가 발생하며 커밋되지 않은 레코드를 읽을 수 있습니다. 실제 상황에서는 사용되지 않습니다.

(2) 읽기 커미트(RC)

이 격리 수준에서는 소위 팬텀 읽기가 발생하는 레코드만 읽을 수 있습니다. 트랜잭션에서 동일한 쿼리가 여러 번 실행되면 반환되는 레코드가 정확히 동일하지 않습니다. 팬텀 읽기의 근본 원인은 RC 격리 수준에서 각 문이 제출된 트랜잭션의 업데이트를 읽는 것입니다. 두 쿼리 사이에 다른 트랜잭션이 제출되면 두 쿼리의 결과가 일치하지 않게 됩니다. 그럼에도 불구하고 읽기-커밋 격리 수준은 프로덕션 환경에서 널리 사용됩니다.

(3) 반복 읽기(RR)

반복 읽기 격리 수준은 반복 불가능 읽기 문제를 해결하지만 여전히 팬텀 읽기 문제는 해결하지 못합니다. 그렇다면 반복 불가능한 읽기와 팬텀 읽기의 차이점은 무엇입니까? 비반복 읽기는 수정, 즉 두 번 읽은 값이 다른 것에 초점을 맞춘 반면, 팬텀 읽기는 레코드 수[삽입 및 삭제]의 변화에 ​​초점을 맞춥니다. 일반적으로 교과서에서는 팬텀 읽기 문제가 직렬화 격리 수준에 도달한 경우에만 해결될 수 있다고 설명하지만 MySQL의 innodb는 주로 GAP 잠금을 통해 팬텀 읽기 문제를 해결합니다. 또한 모든 데이터베이스가 이 격리 수준을 구현하는 것은 아닙니다. 나중에 mysql이 반복 읽기 격리 수준을 구현하는 방법을 간략하게 소개하겠습니다.

(4) 직렬화 가능

직렬 격리 모드에서는 더티 읽기 및 팬텀이 제거되지만 트랜잭션 동시성은 급격히 떨어지며 트랜잭션의 격리 수준은 트랜잭션 동시성에 반비례합니다. 격리 수준이 높을수록 트랜잭션 동시성이 낮아집니다. 실제 프로덕션 환경에서 DBA는 동시성과 비즈니스 요구 사항 충족 사이에서 균형을 이루고 적절한 격리 수준을 선택합니다.

2. 동시 스케줄링 방법

격리 수준과 밀접하게 관련된 또 다른 사항은 격리 수준을 달성하는 동시 스케줄링입니다. 동시 예약의 경우 데이터베이스 공급업체마다 구현 메커니즘이 다르지만 기본 원칙은 모두 잠금을 사용하여 여러 트랜잭션에 의해 동시에 수정되지 않도록 보호합니다. 기존의 잠금 기반 동시성 제어와 비교하여 MVCC(다중 버전 동시성 제어)의 주요 특징은 읽기에 대해 잠그지 않는다는 것입니다. 이 기능은 읽기가 많고 쓰기가 적은 시나리오에서 시스템의 동시성을 크게 향상시킵니다. 따라서 대부분의 관계형 데이터베이스는 모두 MVCC를 구현합니다.

3. 2단계 잠금 프로토콜

2단계 잠금 프로토콜의 의미는 거래가 두 단계로 나뉘며 첫 번째 단계는 봉쇄를 획득하고 두 번째 단계는 해제하는 것입니다. 봉쇄. 2단계 차단은 동시 스케줄링의 정확성을 보장합니다. 1단계 잠금(트랜잭션에 필요한 모든 잠금을 한 번에 획득)과 비교하여 2단계 잠금은 동시성을 향상시키지만 교착 상태의 가능성도 가져옵니다.

4. 교착상태

소위 교착상태란 두 개 이상의 트랜잭션이 상대방이 획득할 것으로 기대하는 자원을 각각 점유하여 대기 루프를 형성하고, 서로 계속할 수 없는 상태를 말합니다. 실행하다.

5. 잠금 유형

잠금 유형에 따라 공유 잠금, 전용 잠금, 의도 공유 잠금, 의도 전용 잠금으로 나눌 수 있습니다. 잠금의 세분성에 따라 행 잠금과 테이블 잠금으로 나눌 수 있습니다. mysql의 경우 트랜잭션 메커니즘은 기본 스토리지 엔진에 의해 더 많이 구현됩니다. 따라서 mysql 레벨에는 테이블 잠금만 있는 반면, 트랜잭션을 지원하는 innodb 스토리지 엔진은 행 잠금(레코드 잠금), 갭 잠금 및 다음 키 잠금을 구현합니다. . Innodb는 인덱스로 구성된 테이블이기 때문에 MySQL의 레코드 잠금은 본질적으로 인덱스 레코드의 잠금입니다. 갭 잠금은 다음 키 잠금에서만 유효한 인덱스 레코드 갭의 잠금입니다. 레코드 잠금과 레코드 잠금 조합 앞의 간격입니다. mysql은 갭 잠금 및 다음 키 잠금을 통해 RR 격리 수준을 구현합니다.

설명:

업링크 잠금은 인덱스를 통해서만 가능합니다. 그렇지 않으면 클러스터형 인덱스의 각 행에 쓰기 잠금이 설정됩니다. 이는 실제로 다음과 같습니다. 테이블에 쓰기 잠금이 있습니다.

여러 물리적 레코드가 동일한 인덱스에 해당하고 동시에 액세스하는 경우 잠금 충돌도 발생합니다.

테이블에 여러 인덱스가 있으면 서로 다른 인덱스를 사용하여 서로 다른 행을 잠글 수 있습니다. 또한 Innodb는 행 잠금을 사용하여 데이터 레코드(클러스터형 인덱스)를 잠급니다.

MVCC 동시성 제어 메커니즘에서는 읽기 작업이 잠겨 있지 않기 때문에 어떤 작업도 읽기 작업을 차단하지 않으며 읽기 작업도 어떤 작업도 차단하지 않습니다.


RocksDB는 오픈 소스 스토리지 엔진으로서 트랜잭션의 ACID 특성을 지원합니다. ACID에서 I(격리)를 지원하려면 동시성 제어가 필수적입니다. 이 기사에서는 주로 RocksDB의 잠금 메커니즘 구현에 대해 설명합니다. 이 글을 통해 독자들이 RocksDB 동시성 제어의 원리를 심도 있게 이해할 수 있기를 바랍니다. 이 기사는 주로 다음 네 가지 측면에서 시작됩니다. 먼저 RocksDB 잠금의 기본 구조를 소개하고 RocksDB 행 잠금 데이터 구조의 잠금 공간 오버헤드를 소개합니다. 그런 다음 몇 가지 일반적인 잠금 프로세스를 소개합니다. 마지막으로 메커니즘의 필수 교착 상태 감지 메커니즘을 소개하겠습니다.

1. 행 잠금 데이터 구조
RocksDB의 최소 잠금 단위는 행입니다. KV 저장소의 경우 잠금 개체가 키이고 각 키는 LockInfo 구조에 해당합니다. 모든 키는 해시 테이블을 통해 관리되며, 잠금을 찾을 때 해시 테이블을 통해 직접 찾아 키가 잠겨 있는지 확인할 수 있습니다. 그러나 전역적으로 해시 테이블이 하나만 있는 경우 이 해시 테이블에 액세스할 때 많은 충돌이 발생하여 동시성 성능에 영향을 미칩니다. RocksDB는 먼저 Columnfamily로 분할됩니다. 각 Columnfamily의 잠금은 LockMap으로 관리되며 각 LockMap은 LockMapStripe로 분할되고 해시 테이블(std::unordered_map946e89586c9a5b7fe5347e04517bbe78acquire_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; //持有锁时间,
}

위 내용은 MySQL 잠금 메커니즘에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.