Mysql 엔진의 잠금(Lock)

Created
March 1, 2024
Created by
D
DaEun Kim
Tags
Mysql
Property

Lock

동시성을 제어하기 위한 기능으로, 스토리지 레벨에서의 lock 과 mysql 엔진 레벨에서의 lock 으로 나뉜다.

Mysql 엔진의 잠금(Lock)

Global Lock

FLUSH TABLES WITH READ LOCK 쿼리를 수행하면 글로벌 락을 획득한다. (엄밀히는 global read lock 획득)

FLUSH TABLES

  • https://dev.mysql.com/doc/refman/8.0/en/flush.html#flush-tables
  • Closes all open tables, forces all tables in use to be closed, and flushes the prepared statement cache.
  • FLUSH TABLES WITH READ LOCK 와 다르게 lock 의 대기/획득 없이 열려 있는 테이블이 있으면 무조건 닫고 prepared statement 삭제 → 운영에서 함부로 쓰지 말자.
  • FLUSH TABLES 는 기본적으로 모든 database 내에 모든 테이블 대상으로 flush 수행.
  • FLUSH TABLES <tbl_name1> <tbl_name2> 과 같이 특정 테이블 대상으로만 flush 수행할 수 있음. 이 때는 테이블 단위로 락 획득.
💡
close opened tables

클라이언트가 테이블(디스크에 있는 파일)에 접근할 수 있도록 커널에서 만들었던 파일 디스크립터들을 없앤다. (파일을 닫는다.)

https://dev.mysql.com/doc/refman/8.0/en/table-cache.html

💡
prepared statement cache

한 세션에서 동일한 구조의 쿼리를 여러번 수행하면 매번 해당 쿼리를 해석하지 않고, 해석한 결과를 캐싱해두는데, 이를 prepared statement 라고 한다.

https://dev.mysql.com/doc/refman/8.0/en/statement-caching.html

FLUSH TABLES WITH READ LOCK

  • https://dev.mysql.com/doc/refman/8.0/en/flush.html#flush-tables-with-read-lock
  • Closes all open tables and locks all tables for all databases with a global read lock.
  • FLUSH TABLES WITH READ LOCK 수행하는 시점에는 테이블들 대상으로 수행중인 쿼리들이 모두 종료되어야 한다. (쿼리들이 종료되기 전 까지 FLUSH TABLES WITH READ LOCK 쿼리는 대기한다.)
  • UNLOCK TABLES 쿼리를 통해 global read lock을 해제하기 전 까지는 SELECT 쿼리를 제외한 다른 세션의DDL/DML 쿼리는 모두 대기해야 한다.
  • mysqldump 프로그램에서 FLUSH TABLES WITH READ LOCK 쿼리를 수행한다.

Backup Lock

FLUSH TABLES WITH READ LOCK 으로 인한 global read lock 은 lock 을 해제할 때 까지 모든 데이터 변경(insert/update/delete)을 막는다.

이는 FLUSH 쿼리로 인해 테이블이 갑자기 닫혀서 partial update 가 발생하는 것을 막기 위함이었는데, 트랜잭션을 지원하는 InnoDB 가 기본엔진으로 채택되면서 불필요하게 되었다. 그리고 8.0 버전부터는 global read lock 대신에 backup lock 을 도입했다.

backup lock 을 해제하기 전 까지는 아래 작업을 수행할 수는 없지만 데이터 변경은 허용된다.

  • DDL
  • REPAIR TABLE , OPTIMIZE TABLE 쿼리
  • 사용자 정보 변경

Backup Lock 의 장점

보통 고가용성을 유지하기 위해 mysql 서버를 1 source, N replica 으로 구성하는데, 백업은 주로 replica 를 대상으로 수행한다.

만약 백업을 위해 replica 서버에서 global read lock 을 생성한다면, 백업이 끝날 때 까지 해당 replica 서버는 source 서버로부터의 복제(insert/update/delete)가 불가능하다. 복제를 못하면 서빙을 못하니 백업이 끝날 때 까지 서비스를 중단해야 하고, 백업이 끝난 후에 최신화를 위한 부가 작업이 필요하게 된다.

이에 비해 backup lock 은 백업을 진행하고 있는 도중에도 source 서버로부터의 복제를 허용하기 때문에 백업과 서빙을 병행할 수 있다.

Table Lock

  • 테이블 단위의 잠금
  • LOCK TABLES <tbl_name> [READ | WRITE] 와 같이 명시적으로 테이블에 락을 획득한다.
  • UNLOCK TABLE 으로 획득한 테이블 락을 해제한다.
  • 테이블 내에 있는 레코드를 대상으로 락을 획득하면 암묵적으로 테이블 대상으로도 락을 획득할 수 있다.
    • 테이블 대상으로 락 획득 → 테이블 내 레코드 변경 → 테이블 대상으로 획득한 락 해제
mysql> start transaction;
mysql> UPDATE delivery SET current_state = 'completed' where id = 1;
mysql> SELECT * FROM performance_schema.data_locks;
+--------+------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+
| ENGINE | ENGINE_LOCK_ID                     | ENGINE_TRANSACTION_ID | THREAD_ID | EVENT_ID | OBJECT_SCHEMA | OBJECT_NAME | PARTITION_NAME | SUBPARTITION_NAME | INDEX_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_MODE     | LOCK_STATUS | LOCK_DATA |
+--------+------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+
| INNODB | 275350782760:3757:275213540392     |                 88204 |        59 |       77 | dispatchyo    | zone        | NULL           | NULL              | NULL       |          275213540392 | TABLE     | IS            | GRANTED     | NULL      |
| INNODB | 275350782760:3758:275213540304     |                 88204 |        59 |       77 | dispatchyo    | delivery    | NULL           | NULL              | NULL       |          275213540304 | TABLE     | IX            | GRANTED     | NULL      |
| INNODB | 275350782760:2693:4:2:275213537392 |                 88204 |        59 |       77 | dispatchyo    | delivery    | NULL           | NULL              | PRIMARY    |          275213537392 | RECORD    | X,REC_NOT_GAP | GRANTED     | 1         |
| INNODB | 275350782760:2692:4:2:275213537736 |                 88204 |        59 |       77 | dispatchyo    | zone        | NULL           | NULL              | PRIMARY    |          275213537736 | RECORD    | S,REC_NOT_GAP | GRANTED     | 1         |
+--------+------------------------------------+-----------------------+-----------+----------+---------------+-------------+----------------+-------------------+------------+-----------------------+-----------+---------------+-------------+-----------+
4 rows in set (0.03 sec)

Named Lock

  • 테이블/레코드/AUTO_INCREMENT 같은 객체가 아니라 단순한 문자열을 대상으로 락을 획득한다.
  • 여러 클라이언트 간의 상호 동기화를 처리해야 할 때 사용한다.
  • == distributed lock
함수 이름
용도
GET_LOCK(str, n)
str 에 대해 락 획득 시도. 락이 이미 걸려있으면 n초 동안 대기.
IS_FREE_LOCK(str)
문자열에 대해 락이 이미 있는지 확인.
RELEASE_LOCK(str)
락 해제.
RELEASE_ALL_LOCKS()
현재 사용하는 세션에서 획득한 모든 락 해제.

Metadata Lock

  • 스키마, 테이블, 함수, 프로시저, GET_LOCK() 을 통해 얻은 user-made lock 등등 데이터베이스 내에서 관리하는 거의 모든 객체의 이름이나 구조를 변경할 때 획득한다.
  • 사용자가 명시적으로 메타데이터 락을 획득/해제할 수 없다.