Insert Ignore 키 충돌과 데드락 발생

Jang990·2025년 5월 16일
0

BookSpot

목록 보기
5/16
post-thumbnail

문제 상황

내가 하고 있던 작업은 1521개의 csv파일에 있는 도서관 소장 도서 데이터(총 1.3억건)에서 유니크한 ISBN13을 가진 책 데이터들을 Book 테이블에 저장하는 것이였다.

결과적으로 유효하고 유니크한 ISBN13을 가진 책 정보는 약 280만개였다.
1.3억개의 데이터는 중복이 굉장히 많은 데이터라는 의미이다.

문제가 발생한 처리 방식

Book 테이블의 ISBN13 필드에 유니크 제약조건을 걸고 Insert Ignore를 통해서 키가 충돌한 경우에는 무시되도록 구현했다.

정말 단순한 방법이다.

Insert Ignore는 충돌이 많을수록 느려지기 때문에
성능을 챙기려고 멀티 스레딩 처리를 진행하면서 진짜 문제가 발생했다.

문제 - 넥스트 키 락 발생과 데드락

DB에 존재하는 ISBN13 데이터를 삽입 시도하면 유니크 제약 조건을 위반하게 되며 duplicate key error가 발생했다.

Insert Ignore이기 때문에 이 에러는 무시된다.

하지만 에러는 무시되지만 락은 잡힌다.
트랜잭션에서 유니크 제약 조건 위반으로 duplicate key error가 발생하면서 넥스트 키 락(레코드 + 갭 락)잡혔다.

이 락은 멀티 스레딩을 진행하면서 데드락의 원인이 됐다.

레코드 락도 원인

TX A : 새로운 ISBN13을 삽입할 때 레코드 락
TX B : TX A 트랜잭션에서 삽입한 ISBN13과 동일한 데이터 삽입 (대기)
이렇게 락을 대기하는 상황에서 TX ATX B에서 먼저 삽입한 ISBN13을 추가 삽입하는 순간 순환구조가 완성되면서 데드락이 터진다.
하지만 중복이 많은 데이터이고, 범위에 락을 잡는 넥스트 키 락이 주 원인일 것이라 생각하기 때문에 넥스트 키락을 위주로 설명한다.

키 충돌과 넥스트 키 락

간단한 테스트 테이블(tb_data)을 구성했다.


테스트 테이블에는 유니크 제약조건이 걸린 unique_field가 있고, 유니크 필드에 데이터 A, C, F가 있다.
한글자만 저장할 수 있다면 저 3가지 데이터 사이에 들어갈 수 있는 데이터는 B, D, E일 것이다.
(오른쪽 사진은 해당 데이터가 들어갈 수 있는 공백을 표시한 사진이다.)

여기서 트랜잭션-1에서 Insert Into tb_data(name, unique_field) values ('ABC', 'C')를 입력하면 유니크 제약조건에 의해 오류가 발생하고, 다음과 같이 넥스트 키 락이 걸리게 된다.

여기서 트랜잭션-2에서 unique_field가 B, D, E 중에 하나라도 시도를 해도 락이 잡혀있기 때문에 바로 Insert를 하지 못한다.

MySQL 락에 대한 자세한 내용은 이 글을 참고하자.
velog - MySQL InnoDB 수준 Lock 종류

넥스트 키 락과 데드락

이번에는 데드락을 살펴보자.

시점트랜잭션실행 SQL락 범위 (Gap/Record Lock)대기 여부설명
1TX-1INSERT INTO tb_data(unique_field) VALUES ('A')(A ~ B)충돌! A~B 락
2TX-2INSERT INTO tb_data(unique_field) VALUES ('F')(D ~ F), (F ~ +∞)충돌! D~F, F~∞ 락
3TX-1INSERT INTO tb_data(unique_field) VALUES ('D')충돌 발생⏳ 대기트랜잭션-2의 D~F 락 대기
4TX-2INSERT INTO tb_data(unique_field) VALUES ('B')충돌 발생⏳ 대기트랜잭션-1의 A~B 락 대기

TX-1과 TX-2간에 순환구조가 만들어지고 데드락이 발생하는 것이다. (락 구분 생략)


이 예시와 같이 이미 DB에 존재하는 ISBN13을 Insert Ignore로 처리하면서 충돌이 발생하고 넥스트 키 락이 잡히면서 데드락이 발생하게 된 것이다.

해결 방법

이 데드락 문제를 해결할 4가지 방법이 있을 수 있다.

  1. 넥스트 키 락 없애기 => 격리 수준을 Read-Commitied로 변경
    넥스트 키 락이 발생하지 않는 격리수준으로 변경하는 방식이다.
  2. 락 경합 없애기 => 싱글 스레드 사용
    데드락이 없도록 단순한 싱글 스레드로 처리하는 방식이다.
  3. duplicate key error 발생 없애기 => 중복 데이터 필터링 후 DB로 보내기
    DB에 이미 존재하는 정보를 없앤 후 Insert하는 방식이다.
  4. 데드락 발생 시 재시도 하기

BookSpot 프로젝트를 진행하면서 Batch 삽입을 진행할 때는
서버에서 필터링해서 Insert하는 3번 방법과, 데드락 발생 시 재시도하는 4번 방법을 사용했다.

profile
공부한 내용을 적지 말고 이해한 내용을 설명하자

0개의 댓글