에그코드 기술 이야기 · 데이터베이스 Lock 시리즈 ⑥ (완결)
안녕하세요, 에그코드입니다.
저희는 자체 서비스를 직접 운영하며 웹·SaaS·MVP를 만드는 개발사입니다.
지난 5편까지 낙관적 락부터 Redisson까지 하나씩 뜯어봤습니다. 그런데 정작 막히는 건 이 질문이죠.
"그래서 내 서비스엔 뭘 써야 하나요?"
마지막 6편은 동시성 제어 선택 기준 3가지를 정리합니다.

기준 1 — 충돌이 얼마나 자주 나는가
가장 먼저 물어볼 건 같은 데이터를 동시에 건드리는 일이 잦은가입니다.
드물다면 낙관적 락입니다. 게시글 수정, 프로필 변경처럼요. 일단 진행하고, 버전이 어긋난 소수만 재시도하면 됩니다.
잦다면 비관적 락입니다. 선착순 쿠폰, 잔액 차감처럼 한 줄에 몰리는 기능이죠.
여기서 낙관적 락을 쓰면 재시도가 눈덩이처럼 불어나 오히려 느려집니다.
| 구분 | 낙관적 락 | 비관적 락 |
|---|---|---|
| 언제 | 충돌이 드물 때 | 충돌이 잦을 때 |
| 방식 | 일단 진행 → 버전 어긋난 것만 재시도 | 먼저 잠그고 시작 (FOR UPDATE) |
| 예시 | 게시글 수정, 프로필 변경 | 선착순 쿠폰, 잔액 차감 |
| 장점 | 대기가 없어 빠르다 | 재시도 없이 한 번에 |

기준 2 — 잠글 자원이 DB 안에 있나, 밖에 있나
여기서부터 동시성 제어의 무게가 달라집니다. 흔한 오해부터 짚고 가죠.
서버가 여러 대로 늘어도 DB 락은 그대로 유효합니다. 서버가 몇 대든 DB가 한 곳에서 심판을 보니까요.
진짜 갈림길은 잠글 대상이 DB 밖에 있을 때입니다. 외부 API 호출, 파일, 캐시처럼요. DB가 모르는 자원이라 걸 데가 없고, 그때 3편의 분산 락이 필요합니다.
분산 락은 "서버가 늘어서"가 아니라, DB 혼자 못 지키는 자원이 생겨서 쓰는 겁니다.

기준 3 — 못 잡았을 때 어떻게 할 것인가
의외로 자주 빠뜨리는 기준입니다. 락은 못 잡았을 때를 정하는 게 절반입니다.
사용자가 기다려도 되는 작업이면 대기가 맞습니다. 기다리면 안 되는 화면이면, 빨리 실패시키고 다시 시도를 안내하는 편이 낫습니다.
무한정 기다리는 설정은 커넥션과 스레드를 붙잡아 장애로 번집니다. 락 하나 때문에 서비스 전체가 멈추는 사고가 여기서 나옵니다.
놓치기 쉬운 것 — 락과 트랜잭션의 순서
가장 조용히 터지는 지점입니다.
분산 락을 트랜잭션 안에서 풀면 문제가 생깁니다. 락은 풀렸는데 커밋은 아직 안 된 찰나가 생기니까요. 그 사이 들어온 다른 서버는 옛날 데이터를 읽습니다. 락을 제대로 걸고도 정합성이 깨지는 겁니다.
락 범위가 트랜잭션 범위보다 바깥이어야 합니다.

정리하며
세 기준을 순서대로 물으면 후보는 대개 좁혀집니다.
다만 어려운 건 기준을 아는 게 아니라, 우리 서비스에 대입하는 일입니다. 충돌 빈도는 기능마다 다르고, 서버는 늘어나고, 트랜잭션 경계는 코드 속에 숨어 있으니까요.
그래서 동시성 제어는 서비스마다 정답이 다릅니다. 저희 에그코드는 자체 서비스를 운영하며 이 판단을 매번 합니다.
결제·재고·예약처럼 어긋나면 곧장 손해가 되는 기능이라면, 설계 단계에서 짚는 편이 훨씬 쌉니다.

데이터베이스 Lock 6부작, 여기서 마칩니다. 낙관적 락부터 전략 선택까지 — 읽어주셔서 고맙습니다.
함께 읽어보세요 — Lettuce 스핀락으로 대기를 구현하는 법 · 데드락과 라이브락, 동시성 함정 2가지 · 에그코드 웹 개발 서비스
동시성 제어나 데이터 정합성 설계가 걱정된다면 편하게 문의 주세요.
동시성·정합성 설계 문의하기