서론
서비스가 성장하면 피할 수 없는 문제가 있습니다. 바로 동시성 제어입니다.
특히 "상품 재고 관리"처럼 여러 사용자가 동시에 같은 자원을 수정하려는 상황에서는 데이터 정합성을 지키는 것이 핵심 과제입니다.
이번 글에서는 Apple M1 Pro(32GB) 환경에서 100개, 1000개 스레드를 동시에 실행하며
세 가지 대표적인 동시성 제어 방식(낙관적 락, 비관적 락, Redis 분산락)을 직접 비교해본 결과를 공유합니다.
실험 환경
- CPU: Apple M1 Pro
- RAM: 32GB
- 테스트 방식:
- CountDownLatch를 사용해 스레드 동시 실행
- 요청마다 같은 상품 재고 -1 업데이트
- 총 요청: 100건, 1000건
CountDownLatch 방식
// 요청 수만큼 스레드 생성 (최대 1000개)
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
CountDownLatch startLatch = new CountDownLatch(1);
// 모든 스레드가 startLatch.await()에서 대기
// startLatch.countDown() 호출 시 모두 동시 실행
Redis 클라이언트 구현체 간 차이

👉 이번 실험에서는 분산환경을 가정해서 Redisson 기반 Redis 분산락을 사용했습니다.
실험 결과
1. 100개 스레드 동시 실행
- 락 없음
- 성공: 100
- 최종 재고: 99 (데이터 불일치 발생)
- 실행시간: 153ms
- 낙관적 락
- 성공: 98 / 실패: 2
- 최종 재고: 2
- 재시도 실패로 일부 요청 누락
- 실행시간: 732ms
- 비관적 락
- 성공: 100
- 최종 재고: 0
- 실행 시간: 232ms
- Redis 분산락
- 성공: 100
- 최종 재고: 0
- 실행 시간: 696ms
2. 1000개 스레드 동시 실행
- 락 없음
- 성공: 1000
- 최종 재고: 992 (정합성 깨짐)
- 실행시간: 1003ms
- 낙관적 락
- 성공: 986 / 실패: 14 (1.4% 실패율)
- 실행 시간: 3.0s
- 재시도 로직 있음에도 retry storm 발생
- 비관적 락
- 성공: 1000
- 최종 재고: 0
- 실행 시간: 1.7s
- Redis 분산락
- 성공: 1000
- 최종 재고: 0
- 실행 시간: 5.0s
결과 분석
1. 낙관적 락 (Optimistic Lock) 에러 발생 지점 분석
현재 재시도 설정
- 최대 시도 횟수: 10회
- 대기(backoff): 시도 사이에 50ms
- 총 재시도 윈도우: 약 500ms (10 × 50ms)
장단점
- 장점: 락 오버헤드 없음, 충돌 적은 환경에서는 최고의 성능
- 🔹 낙관적 락 = 락 오버헤드 없음 + 동시성 확장성 ↑ + 교착상태 없음
- 🔹 비관적 락 = 락 관리 비용 발생 + 대기 큐잉으로 처리량 ↓
- 단점: 경쟁이 심하면 재시도 폭풍 발생 → 실패율 증가
코드 수정없이 할 수 있는 개선 방안
- backoff 시간을 늘리기 (예: 100~200ms) → 충돌 확률 감소
- 고정 지연 대신 지수 백오프(exponential backoff) 사용(지수적으로 백오프 시간 늘리는 것)
- 중요한 작업에는 재시도 횟수 증가
2. 비관적 락 (Pessimistic Lock)이 redis 락 보다 적게 걸린 이유
- 장점: DB 내부 큐잉으로 충돌 없는 일관성 확보
- 단점: 트랜잭션 대기 발생 → 처리량 제한
Redis 분산락
- 장점: 다중 노드 환경에서 강력한 분산 동기화 가능
- 단점: 네트워크 왕복 + 락 획득/해제 비용으로 성능 저하
- 단일 DB 행 경쟁 상황에서는 DB 락보다 불리
- DB 내부의 행 단위 대기 큐잉과 한 번의 트랜잭션 내 처리가 이루어지는 반면, 레디스 락은 네트워크 왕복 + 분산락 획득/해제 비용 + 추가 재시도 대기가 누적되기 때문
- 성능만 보면 이 케이스는 DB 비관적 락이 정답. 레디스 락은 “분산 노드 간” 일관성 보장이 필요할 때 쓰는 선택지지, 단일 DB 행 경쟁에서는 이득이 거의 없다
결론과 가이드
- 단일 DB & 높은 충돌 시나리오:
👉 비관적 락이 가장 안정적이고 빠름 - 충돌이 드문 환경:
👉 낙관적 락이 오버헤드 없이 효율적 - 분산 시스템 (여러 노드/DB):
👉 Redis 분산락이 필수적
앞으로의 고민거리
- Redis 락을 꼭 사용해야한다면 최적화 방법은 뭐가 있을까?
'개발' 카테고리의 다른 글
| null 초기화 전략 (0) | 2025.10.19 |
|---|---|
| MVVM 구조로 리팩토링 (0) | 2025.10.10 |
| 동시성 처리를 위한 락 종류 (0) | 2025.09.20 |
| 비동기 PDF 합성에서 트랜잭션 전파 실패 보완하기 (2) | 2025.08.05 |
| 메모리 성능 개선기 (2) | 2025.07.24 |