피드로 돌아가기
뱅크샐러드 기술블로그Backend
원문 읽기
뱅크샐러드가 게임을 만들 때 데이터 정합성을 유지하는 법 (feat. 낙관적 락)
뱅크샐러드가 현금성 게임 재화 시스템에 낙관적 락(update_version 버전 필드)을 도입해 데이터 정합성 이슈 0건 달성
AI 요약
Context
게임 내 획득한 SAL(현금 전환 가능한 자산)이 유저 직접 액션, 운영자 백오피스 수정, 배치 처리 등 다양한 경로로 동시 업데이트되면서 갱신 손실(Lost Update) 현상이 발생할 수 있었다. 예를 들어 유저의 스킬 보상 200 SAL과 운영자의 CS 보상 500 SAL이 동시에 처리될 때 하나의 변경이 덮어써져 총 1,700 SAL 중 200 SAL이 누락되는 상황이 가능했다.
Technical Solution
- 비관적 락(SELECT ... FOR UPDATE) 대신 낙관적 락 선택: DB 잠금 시간 최소화 및 데드락 위험 제거
- character_state 테이블에 update_version(BIGINT) 필드 추가: 정적 데이터(character)와 동적 데이터(character_state) 분리로 인덱스 리프 노드 경합 감소
- CAS(Compare-And-Swap) 원자 연산 구현: WHERE 절에서 UPDATE 시점에 버전 일치 여부 검증, 불일치 시 업데이트 0건 반환으로 충돌 감지
- 시간 차분(Time-delta) 기반 보상 정산: 마지막 업데이트 시점과 현재 시점의 초 단위 시간 간격 × 초당 보상율로 계산, 실패한 요청의 보상 기간도 다음 성공 시점에 일괄 이월
- 자기 수정(Self-correcting) 아키텍처: 실패한 업데이트는 재시도 로직 없이 이후 유저 액션이나 시스템 이벤트에서 최신 상태 기준으로 재작동하며 자연스럽게 수렴
- Primary DB 조회 강제 및 이벤트 대조 핸들러: 복제 지연(Replication Lag)으로 인한 낡은 데이터 읽음 방지
- 재시도 전략 4원칙: Fresh Read(최신 데이터 재조회), 지수 백오프 + 지터(2^n 형태 간격 + 무작위값), 멱등성 테이블(request_id 기반), 최대 재시도 횟수 제한
Impact
서비스 운영 이후 데이터 정합성 이슈 0건 발생, 유저의 활동에 따른 보상을 1원(SAL)의 오차 없이 정확하게 지급.
Key Takeaway
금융성 자산을 다루는 게임 시스템에서 충돌 확률이 낮은 유저별 격리 데이터 구조라면, 비관적 락이나 분산 락 같은 복잡한 메커니즘 대신 단순한 버전 번호 기반 낙관적 락에 시간 차분 정산 방식을 조합하면 인프라 복잡도를 최소화하면서 데이터 무결성과 응답 성능을 동시에 확보할 수 있다.
실천 포인트
마이크로서비스 환경에서 유저 개인 자산을 다루는 서비스라면, update_version 정수형 필드(타임스탐프 불가)를 추가하고 WHERE 절에서 버전 일치 검증 후 업데이트하는 낙관적 락을 도입하되, 시간 기반 보상 정산 구조를 함께 설계하면 복잡한 재시도 로직 없이도 동시성 제어가 가능하다.