- Commerce 프로젝트의 동시성 이슈가 발생할 수 있는 부분을 공유 자원을 기준으로 식별합니다.
- 각 이슈별 해결 방안을 분석 및 적용합니다.
- 안정적인 서비스 운영을 위한 동시성 제어 전략을 수립합니다.
동시성 이슈의 발생 이유는 여러 스레드 혹은 프로세스가 동시에 공유 자원에 접근하여 변경을 시도했기 때문에 발생합니다. 따라서, 공유 자원과 현재 까지 작성한 비즈니스 로직을 기준으로 동시성 이슈가 발생할 수 있는 목록을 구성했습니다.
- 동일한 사용자가 동시에 두 건 이상의 상품을 주문하여 최종 잔액이 음수가 될 수 있습니다.
- 사용자가 상품을 주문하는 동시에 어드민에서 특정 사용자의 잔액을 차감할 수 있습니다.
- 여러 사용자가 동시에 하나의 쿠폰을 발급할 수 있습니다.
- 여러 사용자가 동시에 1개의 상품에 접근하여 재고가 음수가 될 수 있습니다.
-
개념
- 낙관적 락은 충돌이 발생하지 않을 것이라고 가정하고 충돌이 발생했을 때 사후 처리하는 방식입니다.
- 낙관적 락을 구현하는 방법에는
버전 필드 사용과조건부 업데이트크게 두 가지 존재합니다.
-
장점
- 잠금을 사전에 걸지 않기 때문에 성능이 좋습니다.
- 데드락으로부터 안전합니다.
-
단점
- 충돌시에 재시도 비즈니스 로직을 필요로 합니다.
- 충돌이 잦을수록 성능이 저하됩니다.
-
언제 사용하면 좋을까?
- 충돌 발생 가능성이 낮을 때 사용하면 좋습니다.
- 게시글 수정, 사용자 프로필 업데이트 등
- 충돌 발생 가능성이 낮을 때 사용하면 좋습니다.
- 개념
- 비관적 락은 충돌이 발생할 것이라고 가정하고 미리 잠금을 걸고 처리하는 방식입니다.
- 배타적 잠금(X-Lock)을 사용해서 다른 트랜잭션의 접근을 차단합니다.
- 장점
- 잠금을 걸기 때문에 충돌이 발생하지 않습니다.
- 데이터 정합성 보장이 확실합니다.
- 구현이 단순하고 직관적입니다.
- 단점
- 잠금을 사전에 걸기 때문에 성능 저하가 발생할 수 있습니다.
- 데드락이 발생할 위험이 있습니다.
- 언제 사용하면 좋을까?
- 충돌 발생 가능성이 높을 때 사용하면 좋습니다.
- 데이터 정합성이 중요한 경우에 사용하면 좋습니다.
- 개념
- MySQL Named lock은 사용자 정의 문자열(name)을 기반으로 생성하는 락입니다.
- 데이터베이스의 특정 레코드가 아닌, 논리적인 이름으로 락을 걸 수 있습니다.
- MySQL에서 분산락을 구현하는 수단 중 하나입니다.
- 장점
- Redis 기반 분산락과 비교해서 별도의 인프라 비용 및 관리 비용이 들지 않습니다.
- 단점
- Named lock용 별도 Database connection을 소모하기 때문에 Connection이 마를 위험이 있습니다.
- 언제 사용하면 좋을까?
- Redis를 사용할 수 없는 환경이면서,
- Pessimistic lock으로 해결할 수 없는 경우 (데이터가 존재하지 않아 Lock을 걸 수 없는 경우)
- 참고
- 실무에서는 거의 사용되지 않습니다. (대부분 Pessimistic lock 또는 Redis 분산락으로 해결 가능)
Product 재고는 주문 처리 과정에서 비관적 락(PESSIMISTIC_WRITE, SELECT ... FOR UPDATE)으로 레코드를 먼저 잠근 뒤, 도메인 로직에서 재고를 차감하고 저장하는 방식으로 정합성을 보장합니다. 이 전략은 같은 상품을 다수 사용자가 동시에 주문하더라도 재고가 음수로 내려가지 않도록 합니다.
- 재고는 충돌 가능성이 높은 공유 자원이므로 비관적 락이 적합합니다.
- 도입 후, 동시 주문 통합 테스트에서도 재고가 음수로 내려가거나 중복 차감되는 문제가 재현되지 않았습니다(이미 기존 구현으로 해결되어 별도 이슈가 발생하지 않았음).