2 분 소요

[10분 테코톡] ⛲️ 오즈의 데이터베이스 Lock를 듣고 정리.

락이란 무엇인가

사전적 정의 : 무엇인가 열리지 않도록 하는 장치

데이터베이스에서의 락이란?

→ 락을 사용해서 데이터에 접근을 막을 수 있다. (레코드단위, 테이블단위 등이 있음)

락의 종류

락은 벤더 사마다 조금씩 다른 종류와 전략들을 가진다.

여기서는 MySQL의 InnoDB 스토리지 엔진을 기준으로 설명한다.

배타 잠금(Exclusive Lock)

X lock, exclusive lock 이라고도 한다.

  • Exclusive Lock(X Lock)은 write에 대한 Lock이다.
  • Select … For update, upadate, delete 등의 수정 쿼리를 날릴 때 각 row 에 걸리는 Lock이다
  • 만약 X Lock이 걸려 있으면 다른 트랜잭셔는 S-Lock, X-Lock 둘다 걸 수 없다.

예제

Untitled

트랜잭션 1은 부스0번에 이름을 보토보로 수정한다.

Untitled

트랜잭션 2는 부스 0번에 이름을 픽깃으로 수정하려 한다

하지만 여기서 락이 충돌해서 타임 아웃 에러가발생하게 된다.

Untitled

현재 데이터베이스에 걸린 락의 정보를 알고싶으면 information_schema의 INOODB_LOCKS 테이블을 확인하면 된다.

공유잠금(Shared Locks)

S Lock, Shared Lock이라고도 한다.

  • Shared Lock 은 read에 대한 Lock이다.
  • 일반적인 SELECT 쿼리가아닌 SELECT …. LOCK in SHARE MODE 명령어 를 이용, 또는 SELECT …. FOR SHARE(8.0버전) 을 사용해 read작업을 수행할 때 사용 가능하다.
  • S-Lock 이 걸려있는 row에 다른 트랜잭션이 S-Lock은 걸 수 있으나 X Lock은 걸 수 없다.

예제)

Untitled

트랜잭션 1에서 부스0을 조회하는데 뒤에 lock in share mode라는 명령어를 붙여서 조회한다. 이는 S lock을 명시하면서 조회하는 것을 의미한다.

Untitled

이 상황에서 트랜잭션 2가 pack git으로 부스 0을 수정하려 하자 락에 의한 타임아웃 에러가 발생하는 것을 알 수 있다.

Untitled

마찬가지로 information_schema 데이터베이스의 InnoDB_LOCKS를 조회해보면 S락이 걸려있음을 알 수 있다.

Untitled

이상태에서 트랜잭션 3가 또 다시 share mode로 s lock을 걸면서 조회가 가능하다.

레코드 락(Record Lock)

  • InnoDB에서 레코드 락은 row가 아닌 DB index record에 걸리는 락이다.
  • 테이블에 인덱스가 없다면 테이블 내에 숨겨져 있는 clustered index를 사용하여 레코드를 잠근다.

Untitled

2번 부스에 두 프로젝트가 있어 겹치는 상황.

이에 놀로오세요가 수정을 하려 미리 X-Lock을 걸었다.

이때 여기서 만나가 뒤늦게 수정을 하려 하면 X-Lock에 걸려 요청이 수행되지 않는다.

ex)

Untitled

우선 부스 넘버 칼럼에 인덱스를 추가했다.

Untitled

트랜잭션 1은 2번 부스를 부스넘버를 4로 수정하려 한다.

Untitled

트랜잭션 2는 마찬가지로 동일한 부스넘버인 2번 부스를 5로 수정하려 한다. 이때 락에 걸려 에러가 발생하게된다.

Untitled

즉 락은 동일한 조건의 레코드, Row에 걸릴 수 있다는 것이다.

InnoDB에서는 다른 rdbms들과 달리 테이블레코드가 아닌 인덱스 레코드에 락을 건다.

(앞서 소개했던 X-Lock, S-Lock모두 인덱스 레코드에 걸렸던 것이다)

→ 앞에서는 인덱스를 설정하지 않았는데?? : 숨겨저 있는 clustered Index를 사용해 락을 함.

갭 락(Gap Lock)

  • 인덱스 레코드의 갭에 걸리는 락
  • 갭이란 인덱스 레코드가 없는 부분
  • 조건에 해당하는 새로운 row가 추가되는 것을 방지하기 위한 수단임!

Untitled

부스들 사이에 빈 부스가 많아 새로운 프로젝트가 들어오려고 시도한다.

하지만 1~3, 3~6 사이에 비어있는 공간에 걸린 갭락에 의해 요청을 수행할 수 없는 상황

Untitled

디비의 상황은 다음과 같다. 1, 3, 6번 부스를 제외하고 나머지는 모두 비어있다.

Untitled

트랜잭션 1이 1~6 부스를 for update 구문을 사용해 조회한다. 즉 갭 락을 걸었다.

Untitled

트랜잭션 2는 부스넘버 2,4,5에 삽입을 하려 하지만 전부 락이 걸려있어서 삽입을 할 수 없다.

Untitled

마찬가지로 information schema의 락 테이블에도 갭락이 걸려있음을 확인할 수 있다.

락이 존재해서 디비에서 발생하는 데드락 예제

Untitled

1번부스와 3번부스가 서로를 서로와 바꿔치기 하려는 트랜잭션을 하는 상황이라면 서로에게 걸린 X-Lock으로 인해 데드락이 발생한다.

이노디비에서는 SHOW ENGINE INNODBO STATUS; 라는 명령어로 데드락의 상황을 확인해 볼 수 있다.

Untitled

데드락의 해결

  • deadlock detection이나 lock wait timeout으로 해결한다.
  • deadlock detection이 활성화 되었으면 rollback 할 작은 트랜잭션을 선택하여 롤백을 진행한다고 한다. (이때 크기는 insert, update, delete된 행 수에 의해 결정된다. 벤더사마다다름)
  • deadlock detection이 꺼져있으면 lock wait timeout으로 데드락을 해결한다.

정리

락때문에 장애상황은 반드시 발생하므로 빠른 대처를 위해 필요하다!

댓글남기기