공부

레거시 시스템에서 발생하는 DeadLock에 대한 고찰

ironk.im 2025. 6. 18. 08:57
반응형

3개 이상의 주문 채널이 존재하고 각 주문 채널별 모놀리식 시스템과 단일 DB로 구성된 환경에서 특정 시간 동시 주문 발생 간 데드락이 발생하였고 이에 대한 해결 방법에 대한 사고 실험을 해보고자 한다

 

문제 상황

한개 이상의 상품을 포함하는 주문이 여러 판매 채널로 부터 발생하는 과정에서 상품의 재고 차감 중 데드락이 발생

 

발생 예시

주문1(상품 A, C) 주문2 (상품 B, C, A)
상품 A Lock 상품 B Lock
상품 C Lock 대기 상품 C Lock
  상품 A Lock 대기

 

이처럼 여러 상품을 포함하고 있는 주문 건에 대해 재고 차감 시 데드락이 발생할 수 있다

 

 

락의 종류

1. Optimistic Lock(낙관적 락)

낙관적 락은 version 컬럼을 추가로 두고 업데이트 시 버전을 조건으로 넣어 데이터를 변경하는 방식

조건절에 있는 버전 정보가 맞지 않으면 업데이트가 실패하게 됨으로써 정합성을 보장하는 방법이다

UPDATE ..... WHERE PRODUCT_ID = ? AND VERSION = ?;

 

락을 점유하지 않아 데드락 발생에서 자유롭다

버전 정보가 맞지 않아 업데이트가 실패하는 경우에 대한 재수행 로직이 추가로 구현될 필요가 있다

또한, 충돌이 빈번하게 발생하는 상황(주문이 대량으로 들어오는 상황)에서 반복적인 재수행에 따라 성능 저하가 발생할 수 있다

 

 

2. Pessimistic Lock(비관적 락)

비관적 락은 충돌이 발생할 수 있는 데이터에 접근할 때 해당 데이터에 대한 락을 설정하여 다른 트랜잭션에서 해당 데이터에 대한 변경을 차단하는 방식(행에 대한 락 설정)

SELECT * FROM INVENTORY WHERE PRODUCT_ID = ? FOR UPDATE;
SELECT * FROM INVENTORY WHERE PRODUCT_ID IN (?, ?, ?...) ORDER BY PRODUCT_ID FOR UPDATE;

* 여러 행에 대해 락을 설정하는 경우 ORDER  BY 설정이 중요하다. ORDER BY 설정을 하지 않은 경우 락을 설정하는 행의 순서에 따라 데드락이 발생할 수 있기 때문이다

 

출돌이 발생하기 전에 락을 걸어 차단하기 때문에 충돌 상황에서 안전하게 처리가 가능하다

하지만 트랜잭션 시간이 길거나 상품 수가 많은 경우 성능 저하가 발생할 수 있다

 

3. Distributed Lock(분산 락)

분산 락은 여러 서버들 간의 리소스에 대한 잠금이 필요한 경우 사용하는 것으로 Redis나 Zookeeper 등의 미들웨어를 통해 잠금을 수행한다

 

분산 시스템에 대한 락을 설정할 수 있는 장점이 있으나 미들웨어에 의존하기 때문에 미들웨어의 장애 시 락의 안정성을 보장하기 어렵다(미들웨어의 FailOver 설정 중요)

네트워크 지연이나 TTL 만료 등 고려하지 않으면 중복 실행될 수 있다

 

 

고찰

위와 같은 문제가 발생한 상황과 현재 운영 중인 시스템의 관점에서 보면 낙관적 락을 선택하는게 바람직해 보인다

 

1. 단일 DB이므로 분산 환경 X

2. 동시 발생하는 주문이 많지 않다

3. 데드락 회피 필요

위와 같은 이유로 현재 주어진 상황 속에서 적용할 수 있는 락을 선택하였다

 

!다만, 낙관적 락을 위해서는 변경 실패에 대한 재시도 로직에 대한 추가적인 구현과 기존 코드나 쿼리에 대한 변경이 필요하고, 재시도 횟수에 대한 정책 또한 수립이 필요하다

 

 

사고 실험을 하면서 서비스의 현재 상황과 시스템의 구성 등을 고려하여 가장 적합한 방법을 고민해볼 수 있었다

반응형