낙관적 락 vs 비관적 락
핵심 차이
[비관적 락 (Pessimistic)]
"충돌이 날 거야" → 미리 잠금
TX1: SELECT ... FOR UPDATE ← 락 획득
TX2: SELECT ... FOR UPDATE ← 대기 (블로킹)
TX1: UPDATE → COMMIT ← 락 해제
TX2: 이제 실행 가능
[낙관적 락 (Optimistic)]
"충돌 안 날 거야" → 나중에 확인
TX1: SELECT (version=1)
TX2: SELECT (version=1)
TX1: UPDATE WHERE version=1 → OK (version=2)
TX2: UPDATE WHERE version=1 → 실패! (이미 2)
→ 재시도 필요
비교
| 항목 | 비관적 락 | 낙관적 락 |
|---|
| 방식 | DB 락 (SELECT FOR UPDATE) | 버전 체크 (WHERE version=N) |
| 충돌 시 | 대기 (블로킹) | 실패 → 재시도 |
| 성능 | 충돌 많으면 유리 | 충돌 적으면 유리 |
| 데드락 | 가능 | 불가능 |
| 적합한 경우 | 좌석 예약, 재고 차감 | 게시글 수정, 설정 변경 |
실무 구현
-- 비관적 락: 재고 차감
BEGIN;
SELECT stock FROM products
WHERE id = 1 FOR UPDATE; -- 락!
UPDATE products
SET stock = stock - 1
WHERE id = 1;
COMMIT;
-- 낙관적 락: 게시글 수정
UPDATE posts
SET title = '새 제목',
version = version + 1
WHERE id = 1
AND version = 5; -- 버전 체크
-- affected_rows = 0이면 충돌!
선택 기준
충돌 빈도 높음 (재고, 좌석)
→ 비관적 락 (대기가 재시도보다 저렴)
충돌 빈도 낮음 (프로필, 설정)
→ 낙관적 락 (락 없이 성능 좋음)
분산 환경 (여러 서버)
→ 낙관적 락 선호 (DB 락 범위 제한)
Q.낙관적 락과 비관적 락의 차이를 설명해주세요
충돌을 미리 막는지, 나중에 감지하는지가 다릅니다.
| 항목 | 비관적 락 | 낙관적 락 |
|---|
| 전제 | 충돌이 자주 난다 | 충돌이 드물다 |
| 방법 | 읽을 때부터 잠근다 | 버전을 비교해 갱신 시 확인한다 |
| 구현 | SELECT ... FOR UPDATE | version 컬럼이나 갱신 시각 비교 |
| 대기 | 있다. 다른 트랜잭션이 기다린다 | 없다 |
| 실패 처리 | 거의 없다 | 충돌 시 재시도하거나 사용자에게 알린다 |
| 위험 | 데드락, 대기 누적 | 재시도 폭증 |
기준은 충돌 빈도입니다. 충돌이 드물면 낙관적이 훨씬 빠르고, 잦으면 재시도 비용이 잠금 대기 비용을 넘습니다.
흔한 실수: 낙관적 락을 "잠금을 안 쓰니 항상 빠르다"고 답하는 것. 갱신하는 순간에는 DB 가 행을 잠급니다. 다른 점은 읽는 동안 잠그지 않는다는 것입니다.
Q.쇼핑몰 재고 차감에 어떤 락 방식이 적합한가요? 이유는?
경쟁 정도에 따라 다릅니다. 하나로 답하면 반쯤 틀립니다.
| 상황 | 적합한 방식 |
|---|
| 일반 상품. 초당 주문 0.2건 | 낙관적 락. 충돌이 사실상 없다 |
| 한정 판매. 초당 800건이 재고 100개로 몰린다 | 비관적 락이나 원자적 감소 |
한정 판매에서 낙관적 락을 쓰면 대부분이 충돌해 재시도가 폭증하고, 재시도가 다시 충돌을 키웁니다.
실무에서 자주 쓰는 방법은 조건부 갱신입니다.
UPDATE stock SET qty = qty - 1 WHERE id = ? AND qty > 0
-- 영향받은 행이 0이면 재고 부족
읽고 계산해서 쓰는 것이 아니라 한 문장으로 조건과 갱신을 함께 하므로 경쟁 상태가 생기지 않습니다. 극단적인 경쟁이면 재고를 캐시에서 원자적으로 차감하고 DB 는 나중에 정산하기도 합니다.
흔한 실수: 읽고 확인한 뒤 갱신하는 흐름을 그대로 두고 락만 논하는 것. 문장 하나로 합치는 것이 더 근본적인 해결입니다.
Q.낙관적 락에서 충돌이 발생하면 어떻게 처리하나요?
갱신 시 영향받은 행이 0이면 충돌입니다. 그 다음 처리를 정해야 합니다.
| 처리 | 언제 |
|---|
| 자동 재시도 | 읽고 다시 계산해도 결과가 타당할 때. 재고 차감, 카운터 |
| 사용자에게 알림 | 사람이 판단해야 할 때. 문서 동시 편집 |
| 병합 | 서로 다른 필드를 고쳤다면 합칠 수 있다 |
| 마지막 쓰기 우선 | 정확성이 덜 중요한 값. 조회수, 마지막 접속 시각 |
자동 재시도를 쓸 때는 상한과 대기 시간이 필요합니다.
3회까지, 50ms 100ms 200ms 로 늘려가며
그래도 실패하면 사용자에게 알린다
간격을 늘리는 이유는 같은 간격으로 재시도하면 또 같은 시점에 부딪히기 때문입니다.
흔한 실수: 무한 재시도를 두는 것. 경쟁이 심할 때 서버 부하가 폭증해 상황을 악화시킵니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
데이터베이스 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.