>  기사  >  데이터 베이스  >  MySQL 잠금, 트랜잭션 및 MVCC에 대한 간략한 이해

MySQL 잠금, 트랜잭션 및 MVCC에 대한 간략한 이해

coldplay.xixi
coldplay.xixi앞으로
2020-11-04 17:31:122279검색

mysql tutorial 칼럼에서는 MySQL 잠금, 트랜잭션 및 MVCC에 대한 간단한 이해를 소개합니다.

MySQL 잠금, 트랜잭션 및 MVCC에 대한 간략한 이해

더 많은 관련 무료 학습 권장 사항: mysql 튜토리얼(동영상)

단일 SQL 문이 실행되면 트랜잭션으로 제출되나요?

다음 내용은 "고성능 MySQL"(3판)에서 발췌한 내용입니다

"

MySQL은 기본적으로 자동 커밋(AUTOCOMMIT) 모드를 채택합니다. 즉, 트랜잭션이 명시적으로 시작되지 않는 경우 , 각 쿼리는 커밋 작업을 수행하는 트랜잭션으로 처리됩니다. 현재 연결에서는 AUTOCOMMIT 변수

"

MySQL이 트랜잭션을 구현하는 방법을 설정하여 자동 커밋 모드를 활성화하거나 비활성화할 수 있습니다. 산?

트랜잭션에는 ACID의 네 가지 특성이 있습니다. 그러면 MySQL은 이 네 가지 트랜잭션 특성을 어떻게 구현합니까?

  • 원자적 모두 성공하거나 모두 실패합니다. MySQL은 undo_log를 기록하여 원자성을 달성합니다. undo_log는 rollback log로, 실제 SQL이 실행되기 전에 디스크에 기록된 후 데이터베이스 데이터가 작동됩니다. 예외나 롤백이 발생하면 undo_log를 기반으로 역방향 작업을 수행하여 트랜잭션이 실행되기 전의 데이터를 복원할 수 있습니다.

  • 끈기 트랜잭션이 정상적으로 커밋되면 데이터베이스에 미치는 영향은 영구적이어야 합니다. 이때 시스템이 충돌하더라도 수정된 데이터는 손실되지 않습니다. InnoDB는 MySQL의 스토리지 엔진으로 데이터가 디스크에 저장된다. 그러나 데이터를 읽고 쓸 때마다 디스크 IO가 필요하면 효율성이 매우 떨어진다. 이를 위해 InnoDB는 데이터베이스에 접근하기 위한 버퍼로 캐시(Buffer Pool)를 제공하는데, 데이터베이스에서 데이터를 읽을 때 버퍼 풀에 없으면 먼저 읽어온다. 데이터베이스에 데이터를 쓸 때 먼저 버퍼 풀에 기록되고 버퍼 풀의 수정된 데이터가 정기적으로 디스크에 새로 고쳐집니다.

    이러한 설계는 또한 상응하는 문제를 가져옵니다. 데이터가 제출되고 데이터가 여전히 버퍼 풀에 있는 경우(디스크가 아직 플러시되지 않은 경우) MySQL이 다운되거나 전원이 꺼지면 어떻게 해야 합니까? 데이터가 손실되나요?

    대답은 '아니오'입니다. MySQL은 redo_log 메커니즘을 통해 내구성을 보장합니다. redo_log는 redo 로그입니다. 간단히 말해서, 데이터가 수정되면 버퍼 풀의 데이터를 수정하는 것 외에도 트랜잭션이 제출될 때 작업이 redo_log에 기록되고 fsync 인터페이스가 호출됩니다. redo_log. MySQL이 다운되면 redo_log의 데이터를 읽고 다시 시작할 때 데이터베이스를 복구할 수 있습니다.

  • Isolation

    Isolation은 ACID에서 가장 복잡한 것으로, 총 4가지의 격리 레벨이 있습니다

    • Read uncommitted
    • Read commit
    • 반복 읽기 가능.
    • Serialized

    간단히 말해서 격리 수준은 다음을 규정합니다. 트랜잭션의 데이터 수정, 어떤 트랜잭션이 표시되고 표시되지 않는지. 격리는 여러 동시 읽기 및 쓰기 요청의 액세스 순서를 관리하는 것입니다.

    MySQL의 구체적인 격리 구현에 대해서는 나중에 논의할 것입니다.

  • 일관성

    동시 환경에서 롤백, 복구, 격리를 통해 일관성을 달성하세요.

트랜잭션 동시성으로 인해 발생할 수 있는 문제

앞의 질문을 통해 단일 DDL 실행도 자동으로 트랜잭션으로 제출된다는 것을 알고 있으므로 동시에 여러 SQL이든 다중 수동으로 여러 SQL 문을 포함하는 조직의 트랜잭션 동시성은 트랜잭션 동시성 문제를 발생시킵니다.

구체적으로:

  • 더티 쓰기(한 트랜잭션에서 제출한 데이터가 다른 트랜잭션의 커밋되지 않은 데이터를 덮어씀)
  • 더티 읽기(한 트랜잭션이 다른 트랜잭션의 커밋되지 않은 데이터를 읽음)
  • 반복 불가능한 읽기(핵심 사항) 업데이트와 삭제의 한 트랜잭션에서 여러 번 읽은 데이터가 다르다는 것입니다)
  • 팬텀 읽기 (핵심은 삽입의 한 트랜잭션에서 여러 번 읽은 레코드 수가 다르다는 것입니다)

앞서 언급한 바가 있습니다 위의 트랜잭션 격리 수준 MySQL의 모든 격리 수준은 더티 쓰기가 발생하지 않도록 보장하므로 남은 문제는 더티 읽기, 반복 불가능한 읽기 및 팬텀 읽기뿐입니다.

각 격리 수준이 위의 문제를 어떻게 해결하거나 해결하지 못하는지 자세히 살펴보겠습니다.

Read uncommitted

Uncommitted 읽기, 이 수준은 읽기 프로세스 중에 잠금을 추가하지 않습니다. , 요청을 쓸 때만 잠기므로 쓰기 작업은 읽기 프로세스 중에 데이터를 수정하므로 더티 읽기가 발생합니다. 반복 불가능한 읽기와 팬텀 읽기는 자연스럽게 발생합니다.

커밋된 읽기

커밋된 읽기는 커밋되지 않은 읽기와 마찬가지로 읽기용으로 잠기지 않고 쓰기용으로 잠겨 있습니다. 차이점은 더티 읽기(dirty read) 문제를 방지하기 위해 MVCC 메커니즘이 사용된다는 것입니다. 반복 불가능한 읽기 및 팬텀 읽기 문제도 있습니다. MVCC에 대해서는 나중에 자세히 설명하겠습니다.

반복 읽기

MySQL 기본 격리 수준에서 MySQL은 문제를 해결하기 위해 두 가지 방법을 사용합니다.

  1. 읽기-쓰기 잠금 병렬로 읽을 때 읽기 잠금이 추가되며, 읽기와 읽기는 잠금을 공유합니다. 쓰기 요청이 있는 한 쓰기 잠금이 추가되어 읽기와 쓰기가 연속적으로 이루어집니다. 데이터를 읽을 때 잠금이 수행되며 다른 트랜잭션은 데이터를 수정할 수 없습니다. 따라서 반복 불가능한 읽기가 발생하지 않습니다. 데이터를 수정하고 삭제할 때도 잠금이 필요합니다. 다른 트랜잭션은 데이터를 읽을 수 없으므로 더티 읽기가 발생하지 않습니다. 첫 번째 방법은 우리가 흔히 "비관적 잠금"이라고 부르는 방법입니다. 전체 트랜잭션 프로세스 동안 데이터가 잠기는데, 이는 상대적으로 보수적이며 성능 오버헤드가 상대적으로 큽니다.
  2. MVCC(추후 논의)

또한, 팬텀리딩 문제를 어느 정도 해결하기 위해 Next-Key 잠금도 사용됩니다. 이에 대해서는 나중에 이야기하겠습니다.

Serialized

이 격리 수준에서는 트랜잭션이 순차적으로 실행됩니다. 자동 커밋이 비활성화된 경우 InnoDB는 모든 일반 SELECT 문을 암시적으로 SELECT ... LOCK IN SHARE MODE로 변환합니다. 즉, 읽기 공유 잠금이 읽기 작업에 암시적으로 추가되어 더티 읽기, 반복 불가능 읽기 및 팬텀 읽기 문제를 방지합니다. 다중 버전 동시성 제어(MCC 또는 MVCC)는 데이터베이스에 대한 동시 액세스를 제공하고 트랜잭션 메모리를 구현하기 위해 프로그래밍 언어로 데이터베이스 관리 시스템에서 일반적으로 사용되는 동시성 제어 방법입니다.

번역의 의미: 다중 버전 동시성 제어(MCC 또는 MVCC)는 일반적으로 데이터베이스 관리 시스템에서 데이터베이스에 대한 동시 액세스를 제공하고 프로그래밍 언어로 트랜잭션 저장소를 구현하는 데 사용되는 동시성 제어 방법입니다. 간단히 말하면 데이터베이스에서 동시성을 제어하기 위해 사용하는 방법입니다. 각 데이터베이스에는 서로 다른 MVCC 구현이 있을 수 있습니다.

우리가 일반적으로 사용하는 MySQL을 예로 들면, MySQL의 InnoDB 엔진은 MVCC를 구현합니다.

MVCC가 해결할 수 있는 문제

위 정의에서 MVCC는 주로 트랜잭션 동시성 중 데이터 일관성 문제를 해결한다는 것을 알 수 있습니다

InnoDB가 MVCC를 구현하는 방법

아래 그림은 "고성능 MySQL"(3판)에서 가져온 것입니다.

이 책은 잘 쓰여지고 잘 번역되었습니다. 하지만 개인적으로 MVCC 구현 방법에 대한 설명에는 몇 가지 문제가 있다고 생각합니다.

어디가 문제인지 살펴보겠습니다

  • 먼저 MySQL 공식 문서를 살펴보겠습니다. 5.1, 5.6, 5.7 세 가지 버전[1]문서를 비교했습니다. MVCC의 이 부분을 설명하는 내용은 거의 동일합니다.

문서에 따르면 각 데이터 조각에 3개의 숨겨진 열이 추가된 것이 분명합니다.

  • 6바이트 DB_TRX_ID 필드는 가장 최근에 삽입되거나 업데이트된 트랜잭션 ID를 나타냅니다. 기록.
  • 7바이트 DB_ROLL_PTR 필드는 해당 레코드의 롤백 세그먼트에 대한 실행 취소 로그 레코드를 가리킵니다.
  • 6바이트 DB_ROW_ID. 새 데이터가 삽입되면 자동으로 증가됩니다. 테이블에 사용자 기본 키가 없으면 InnoDB는 DB_ROW_ID 필드를 포함하여 클러스터형 인덱스를 자동으로 생성합니다.

여기에 롤백 세그먼트를 포함한 MySQL 내부 구조 다이어그램을 추가합니다

버전 체인

앞에서 undo_log의 개념에 대해 이야기했습니다. 버전 체인의 헤드 노드는 현재 레코드의 최신 값입니다.

읽기보기

열과 버전 체인을 숨김으로써 MySQL은 데이터를 지정된 버전으로 복원할 수 있지만 복원할 버전은 ReadView에 따라 결정되어야 합니다. 소위 ReadView는 트랜잭션(트랜잭션 A로 기록됨)이 특정 순간에 전체 트랜잭션 시스템(trx_sys)의 스냅샷을 찍는 것을 의미하며, 나중에 읽기 작업이 수행될 때 읽기 데이터의 트랜잭션 ID와 비교됩니다. trx_sys 스냅샷을 통해 데이터가 ReadView에 표시되는지, 즉 트랜잭션 A에 표시되는지 여부를 결정합니다.

지금까지 우리는 MVCC가 숨겨진 필드, undo_log 체인 및 ReadView를 기반으로 구현된다는 것을 발견했습니다.

읽기 커밋의 MVCC

이전에 우리는 더티 읽기 문제를 해결하기 위해 읽기 커밋 격리 수준에서 MVCC를 사용하는 방법에 대해 이야기했습니다. 여기서는 두 가지 기사를 참조합니다.

  • https://cloud.tencent.com/developer/article/1150633
  • https://cloud.tencent.com/developer/article/1150630

InnoDB 버전이 현재 트랜잭션 버전보다 이전인 데이터 행만 찾습니다(즉, 행의 버전 번호가 트랜잭션의 시스템 버전 번호보다 작거나 같음). 트랜잭션이 시작되기 전에 이미 존재하며 트랜잭션 자체에 의해 삽입되거나 수정됩니다. 그러면 더티 읽기가 발생하지 않습니다.

commitRead 격리 수준에서 반복 불가능한 읽기는 읽기 보기의 생성 메커니즘으로 인해 발생합니다. Read 커밋 수준에서는 현재 문이 실행되기 전에 커밋된 데이터가 표시됩니다. 각 명령문 실행 중에 읽기 보기가 닫히고 현재 읽기 보기가 다시 생성됩니다. 이러한 방식으로 현재 글로벌 트랜잭션 목록을 기반으로 읽기 뷰의 트랜잭션 간격을 생성할 수 있습니다. 간단히 말해서, 읽기 커밋 격리 수준에서 MVCC는 각 선택에 대해 스냅샷 버전을 생성하므로 각 선택은 서로 다른 버전의 데이터를 읽으므로 반복 불가능한 읽기가 발생합니다.

반복 읽기 격리 수준은 트랜잭션의 여러 읽기가 다른 결과를 생성하지 않아 반복 읽기를 보장합니다. 이전 기사에서 반복 읽기에는 두 가지 구현 방법이 있다고 말했습니다. 하나는 비관적 잠금 방법이고 반대쪽은 MVCC가 낙관적 잠금 방법입니다.

반복 읽기 격리 수준은 반복 불가능 읽기 문제를 해결할 수 있습니다. 근본적인 이유는 읽기 뷰의 생성 메커니즘이 읽기 커밋의 생성 메커니즘과 다르기 때문입니다.

  • 읽기 커밋: 현재 명령문이 실행되기 전에 커밋된 데이터가 표시되는 한.
  • 반복 읽기: 현재 트랜잭션이 실행되기 전에 제출된 데이터가 표시되는 한.

읽기 커밋과 달리 반복 읽기 격리 수준에서 트랜잭션이 생성되면 현재 전역 읽기 뷰가 생성되어 트랜잭션이 끝날 때까지 유지됩니다. 이를 통해 반복 가능한 읽기가 가능해집니다.

팬텀 읽기 및 다음 키 잠금

현재 읽기 및 스냅샷 읽기

MVCC 메커니즘을 통해 데이터는 반복 가능하지만 우리가 읽는 데이터는 기록 데이터입니다. , 시기적절한 데이터가 아니고 데이터베이스의 현재 데이터가 아닙니다! 이러한 기록 데이터 읽는 방법을 스냅샷 읽기(스냅샷 읽기)라고 하고, 현재 버전의 데이터베이스 데이터를 읽는 방법을 현재 읽기(현재 읽기) Reference[3]이라고 합니다.

  • 스냅샷 읽기: select
    • select * from table….;
  • 현재 읽기: 특수 읽기 작업, 삽입/업데이트/삭제 작업, 현재 읽기에 속하며 현재 처리되는 데이터 잠가야 합니다.
    • 공유 모드에서 *를 선택하세요.
    • 업데이트를 위해 테이블에서 *를 선택하세요.
    • 순서대로
    • 현재 읽기
      의 팬텀 읽기 문제를 해결하기 위해 MySQL 트랜잭션은 다음 키 잠금을 사용합니다.

      반복 읽기는 다음 키 잠금 메커니즘을 통해 가상 읽기를 방지합니다.

      InnoDB 스토리지 엔진에는 다음과 같은 3개의 행 잠금 알고리즘이 있습니다.

      • Record Lock: 단일 레코드에 대한 잠금
      • Gap Lock: Gap Lock, 범위를 잠그지만 레코드를 포함하지 않음
      • 다음 키 잠금: 갭 잠금 + 레코드 잠금

      다음 키 잠금은 행 잠금 유형으로, 레코드 잠금 + 갭 잠금과 동일하며 그 특징은 레코드 자체를 유지할 뿐만 아니라(기능) 기록 잠금 기능), 범위 잠금 기능(갭 잠금 기능)도 있습니다.

      InnoDB가 인덱스 레코드를 스캔할 때 먼저 인덱스 레코드에 행 잠금(Record Lock)을 추가한 다음 인덱스 레코드 양쪽의 간격에 간격 잠금(Gap Lock)을 추가합니다. 갭 잠금을 추가한 후에는 다른 트랜잭션이 이 갭의 레코드를 수정하거나 삽입할 수 없습니다.

      쿼리된 인덱스에 고유 속성이 포함된 경우 Next-Key Lock이 최적화되어 범위가 아닌 인덱스 자체만 잠그는 Record Lock으로 다운그레이드됩니다.

위 내용은 MySQL 잠금, 트랜잭션 및 MVCC에 대한 간략한 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.im에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제