사용자 도구

사이트 도구


database:mysql:user_lock

MySQL User Lock

  • MySQL에서 GET_LOCKRELEASE_LOCK 으로 분산 락(distributed lock)을 구현할 수 있다.
  • 원래는 Redis Distributed Lock를 사용하려다가 서버 구성하고 관리하는게 힘들어서 어차피 사용하는 MySQL에 적용했는데, 너무 잘 작동해서 Redis Distributed Lock 을 사용할 필요가 없어졌다.
  • MySQL의 User Level Lock를 활용한다면? user level lock의 활용에 대해 잘 설명한 글
  • 동일 커넥션에서 GET_LOCK을 여러번하면 여러번 락이 잡힌다. 따라서 RELEASE_LOCK을 그 횟수만큼 동일 커넥션에서 반복해서 해주지 않으면 lock이 풀리지 않게 된다.
    • 위 문제에 따라 Java에서 Connection Pool 사용시 항상 동일 Lock 문자열에 대한 GET_LOCK과 RELEASE_LOCK 이 동일 커넥션에서 동일 횟수만큼 이뤄짐을 보장해줘야 한다.
    • 이 문제를 해결하려면 Spring Framework의 트랜잭션에 의존하지 말고, 별도의 DataSource를 생성하여 직접 Lock 용 커넥션과 트랜잭션을 컨트롤하는 것이 좋다.
  • Lock 은 트랜잭션 commit/rollback 여부와 상관없이 작동한다. rollback 한다고해서 lock 이 풀리지는 않는다.
  • Performance schema의 metadata_locks 테이블에 관련 정보가 저장된다.
  • Lock 이름은 64글자 제한(from MySQL 5.7)
--  lock 잡기. 숫자 1은 lock 을 잡기 위해 대기할 수 있는 최대시간.
-- 이 시간안에 락을 잡지 못하면 0 반환.
SELECT get_lock('session key', 1);
 
-- 배타적으로 할 일.
 
-- 락 풀기
SELECT release_lock('session key');
  • MySQL 5.6은 GET_LOCK을 동일 세션에서 연속 호출하면 앞선 Lock을 해지하고 다시 잡는다.
  • MySQL 5.7은 두번 이상 호출해도 앞선 락을 해지하지 않는다.
  • 5.7 부터 하나의 세션에서 연속으로 동일 Lock 이름으로 Lock을 잡으면 그 횟수만큼 중복으로 Lock이 잡힌다.
SELECT get_lock('a', 1);
SELECT is_free_lock('a'); -> FALSE
SELECT get_lock('a', 1);
SELECT is_free_lock('a'); -> FALSE
 
-- release 시작
SELECT release_lock('a'); -> 1
SELECT is_free_lock('a'); -> FALSE
 
SELECT release_lock('a'); -> 1
SELECT is_free_lock('a'); -> TRUE
 
-- 이미 모든 Lock 해지 상태
SELECT release_lock('a'); -> NULL

참조

database/mysql/user_lock.txt · 마지막으로 수정됨: 2023/05/05 22:03 저자 kwon37xi