피드로 돌아가기
The race condition a stress test found in my double-entry ledger — and how I fixed it
Dev.toDev.to
Backend

Optimistic Locking과 Bounded Retry를 통한 Ledger 시스템의 Lost Update 원천 차단

The race condition a stress test found in my double-entry ledger — and how I fixed it

Do Pham Dinh2026년 5월 24일9advanced

Context

Double-entry 원칙의 Append-only Ledger 구조에서 조회 성능 최적화를 위해 도입한 Balance Cache가 Read-Modify-Write Race Condition을 유발함. PostgreSQL의 READ COMMITTED 격리 수준만으로는 동시 요청 시 발생하는 데이터 덮어쓰기(Lost Update)를 방지하기에 불충분한 한계가 존재함.

Technical Solution

  • JPA @Version 기반의 Optimistic Locking을 도입하여 Update 시점의 Compare-and-Set 검증을 통한 데이터 무결성 확보
  • OptimisticLockingFailureException 발생 시 Transaction 외부에서 Bounded Retry 로직을 수행하여 사용자 경험 저하 방지
  • Retry 횟수 증가에 따른 부하 분산을 위해 지수 백오프(Exponential Backoff)와 Jitter를 적용한 재시도 메커니즘 설계
  • Idempotency Key를 통한 요청 식별을 선행하여 Retry 과정에서 발생할 수 있는 중복 출금(Double-spending) 위험 제거
  • Ledger Entry의 합계와 Cache Balance를 상시 비교하는 Reconciliation Job을 배치하여 데이터 정합성 상시 감시

1. Read-Modify-Write 패턴 적용 시 DB 격리 수준이 Lost Update를 막아주는지 검증했는가?

2. Optimistic Locking 도입 시 실패한 트랜잭션에 대한 Retry 전략과 최대 재시도 횟수가 정의되었는가?

3. Retry 로직이 Idempotency 보장 계층보다 하위에 위치하여 중복 처리 위험을 제거했는가?

4. State-derived Cache의 정합성을 주기적으로 검증하는 Reconciliation 프로세스가 존재하는가?

원문 읽기