Mysql 엔진의 잠금(Lock)

Created
Mar 1, 2024
Created by
Tags
Mysql
Property
 

Lock

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

Mysql 엔진의 잠금(Lock)

Global Lock

FLUSH TABLES WITH READ LOCK 쿼리를 수행하면 글로벌 락을 획득한다. (엄밀히는 global read lock 획득)
 
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
클라이언트가 테이블(디스크에 있는 파일)에 접근할 수 있도록 커널에서 만들었던 파일 디스크립터들을 없앤다. (파일을 닫는다.)
💡
prepared statement cache
한 세션에서 동일한 구조의 쿼리를 여러번 수행하면 매번 해당 쿼리를 해석하지 않고, 해석한 결과를 캐싱해두는데, 이를 prepared statement 라고 한다.
 
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 등등 데이터베이스 내에서 관리하는 거의 모든 객체의 이름이나 구조를 변경할 때 획득한다.
  • 사용자가 명시적으로 메타데이터 락을 획득/해제할 수 없다.