밤마다 뜨던 데드락, 잠그는 순서를 고정하니 사라졌다

포인트 정산 배치가 밤마다 몇 건씩 실패했다. 로그엔 이 한 줄.

Deadlock found when trying to get lock; try restarting transaction

재시도하면 성공하니 넘어갈 뻔했는데, 원인을 안 잡으면 트래픽 늘 때 폭발할 종류의 버그라 파고들었다.

두 트랜잭션이 서로 반대 순서로 잠갔다

정산 로직이 두 계좌 사이에 포인트를 옮기는 구조였는데, 어떤 트랜잭션은 A를 잠그고 B를 잠그려 하고, 다른 트랜잭션은 B를 잠그고 A를 잠그려 했다. 서로가 상대가 쥔 락을 기다리며 물고 물리는 순환이 생겼다. DB는 이걸 감지하면 한쪽을 강제로 죽여서 푼다. 그게 위 에러다.

잠그는 순서를 고정

해결은 의외로 단순했다. 여러 행을 잠글 때 항상 같은 기준, 여기서는 계좌 ID 오름차순으로 정렬해서 잠그도록 통일했다. 모든 트랜잭션이 같은 순서로 락을 잡으면 순환이 생길 수가 없다. 정렬 한 줄 넣었을 뿐인데 밤마다 뜨던 데드락이 사라졌다. 물론 순간적 충돌에 대비해 재시도 로직은 그대로 뒀다. 데드락은 완전히 없앤다기보다 확률을 0에 가깝게 낮추고 나머지는 재시도로 흡수하는 문제였다.