[Spring] 낙관적 락 / 비관적 락 비교하기

2025. 7. 23. 23:59·Spring Framework/Spring
반응형

한정된 수량의 쿠폰을 회원에게 발급하는 시스템에서는 동시 다발적인 요청으로 인해 동시성 문제가 발생할 수 있다. 선착순 쿠폰 발급 시나리오에서 낙관적 락과 비관적 락의 성능을 정량적으로 비교하고, 동시 접속자 수 변화에 따른 각 방식의 특성을 분석했다.


실험 환경

기술 스택

  • Backend : Spring Boot, Spring Data JPA, PostgreSQL
  • 부하 테스트 : K6
  • 실행 환경 : 로컬 개발 환경 (단일 서버)

시스템 설정

별다른 튜닝은 적용하지 않았다.

  • HikariCP max-pool-size: 20
  • Tomcat max-threads: 100

락 구현 방식

  • 비관적 락 (SELECT FOR UPDATE)
  • 낙관적 락 + 재시도 3회 + Exponential Backoff
  • 낙관적 락 + 재시도 10회 + Exponential Backoff
// 낙관적 락 충돌 발생 시 일정 시간 대기 후 재시도
long sleepTime = (long) (50 * Math.pow(1.5, retryCount));
Thread.sleep(Math.min(sleepTime, 500));  // 최대 500ms

테스트 시나리오

기본 설정

  • 쿠폰 총 수량 : 1,000개
  • 신청자 수 : 1,000명 (경쟁률 1:1)
  • 동시 접속자 수(VUS) : 10, 50
    • 낮은 충돌(10), 빈번한 충돌(50)로 가정했다.
  • 동시 접속자 수 변화에 따른 각 락 방식의 성능 및 정합성 비교

측정 지표

  • 정합성 : 최종 발급된 쿠폰 수가 총 수량(1,000개)과 일치하는지 확인
  • 성능
    • 평균 응답 시간 : 모든 요청의 평균 처리 시간
    • P95 응답 시간 : 상위 5%를 제외한 95%의 요청이 완료된 시간 (일반적 사용자 경험)
    • P99 응답 시간 : 상위 1%를 제외한 99%의 요청이 완료된 시간 (최악 케이스 제외)
    • 최대 응답 시간 : 가장 오래 걸린 요청의 응답 시간 (최악의 사용자 경험)
    • TPS : 초당 처리 가능한 트랜잭션 수 (시스템 처리량)
  • 낙관적 락을 위한 추가 지표
    • 평균 재시도 횟수 : 성공한 요청의 평균 재시도 횟수
    • 총 재시도 횟수 : 모든 성공 요청의 재시도 합계
    • 재시도 초과 : 최대 재시도 후에도 실패한 요청 수

실험 결과

VUS 10 (저동시성 상황)

지표 비관적 락 낙관적 락(재시도 3회) 낙관적 락(재시도 10회)
발급 성공 1,000개 (100%) 898개 (89.8%) 997개 (99.7%)
평균 응답시간 55ms 90ms 150ms
P95 74ms 399ms 667ms
P99 83ms 411ms 1,635ms
최대 응답시간 109ms 578ms 3,610ms
TPS 60.4/s 37.7/s 36.5/s
총 재시도 횟수 - 652회 905회
재시도 초과 - 102건 3건
평균 재시도 - 0.73회 0.91회
  • 비관적 락만 모든 수량의 쿠폰을 발급 성공했다.
  • 응답 시간은 비관적 락이 가장 안정적이었다.
    • 평균 응답시간 : 비관적 락 55ms vs 낙관적 락(3회) 90ms (1.6배)
    • P99 : 비관적 락 83ms vs 낙관적 락(10회) 1,635ms (19.7배)
  • 비관적 락이 가장 높은 처리량을 보였다 (60.4 TPS)
  • 낙관적 락 충돌 : 동시 접속 10명에서도 652~905회의 재시도 발생했다.

동시 접속 10명 수준의 저동시성 환경에서도 낙관적 락은 빈번한 충돌이 발생하여 정합성을 보장하지 못했다. 재시도를 10회까지 늘려도 0.3%의 미발급이 발생했으며, P99 응답 시간이 비관적 락 대비 19.7배 느려졌다. 낙관적 락 사용 시 충돌 발생으로 인한 재시도가 응답 지연의 원인으로 보인다.

 

 


VUS 50 (고동시성 상황)

지표 비관적 락 낙관적 락(재시도 3회) 낙관적 락(재시도 10회)
발급 성공 1,000개 (100%) 564개 (56.4%) 946개 (94.6%)
평균 응답시간 463ms 230ms 436ms
P95 744ms 554ms 1,777ms
P99 1,010ms 613ms 3,441ms
최대 응답시간 1,033ms 649ms 4,448ms
TPS 55.0/s 60.3/s 45.0/s
총 재시도 횟수 - 350회 708회
재시도 초과 - 436건 54건
평균 재시도 - 0.62회 0.75회
  • VUS50가 정말 큰 동시접속자 수는 아니지만 VUS10에 비해 크기 떄문에 고동시성으로 명명헀다.
  • 여전히 비관적 락만 모든 수량의 쿠폰을 발급했다.
    • 낙관적 락 방식은 발급 성공 수량이 조금 하락했다. 충돌이 빈번해져 발급 성공 케이스가 감소했다.
  • 낙관적 락은 불안정한 응답 시간 지연이 발생한다.
    • P99 : 비관적 락 1,010ms vs 낙관적 락(10회) 3,441ms (약 3.4배)
    • 낙관적 락 방식의 경우 최대 응답 지연시간이 4,448ms로 일부 사용자는 4초 이상 대기하게 된다.

동시 접속자가 10명에서 50명으로 증가하자 낙관적 락의 성능이 급격히 저하되었다. 재시도 3회로는 절반 가까이 실패했으며, 재시도 10회로도 5.4%가 실패하고 응답 시간이 극도로 불안정해졌다. 반면 비관적 락은 여전히 100% 정합성을 유지하며 안정적인 성능을 보였다.

결론

  • 비관적 락은 완벽한 정합성을 보장했다. 락 대기로 인한 응답 시간 증가가 있지만 정합성이 중요한 곳에 적합하다.
  • 낙관적 락은 이론상 락 오버헤드가 없어 빠를 것으로 예상하지만, 충돌이 빈번한 상황에서는 오히려 불안정한 응답 지연을 보였다.
  • 이벤트성 쿠폰 발급의 상황에서는 비관적 락을 사용하는게 실용적 선택이 될 같다.
    • 낙관적 락은 저동시성 상황에서도 실패가 발생했으며, 재시도로 인한 보완 시도 시 응답시간이 크게 증가했다.
    • 비관적 락은 정합성을 지키며 안정적인 성능을 제공했다.

이론으로만 학습했던 낙관적 락과 비관적 락을 직접 구현하고 실험해보니 각 방식의 특성을 공부할 수 있었다. 특히 낙관적 락은 충돌이 적은 환경에서 유리하다는 이론을 직접 확인해 봐서 의미있었다.
실험 과정에서 트랜잭션 범위 설정 실수를 발견하고 수정하거나, K6 메트릭을 분석하는 등 동시성 제어 외에도 많은 것을 배울 수 있었다. 이번 실험을 토대로 다음에는 레디스를 활용한 분산 락 방식도 비교해보고 싶다. 추가로 커넥션 풀 사용량, GC 빈도, CPU 사용률 등 시스템 리소스 지표를 함께 측정해보면 좋을 것 같다.

 

 

반응형
저작자표시 비영리 변경금지 (새창열림)
'Spring Framework/Spring' 카테고리의 다른 글
  • [Spring] tomcat 설정의 동작 원리(max-connections, accept-count, threads.max)
  • [Spring] 트랜잭션과 동시성
  • [Spring Batch] 메타 데이터 테이블 정리
  • [Spring Batch] skip / retry
덴마크초코우유
덴마크초코우유
IT, 알고리즘, 프로그래밍 언어, 자료구조 등 정리
    반응형
  • 덴마크초코우유
    이것저것끄적
    덴마크초코우유
  • 전체
    오늘
    어제
    • 분류 전체보기 (132)
      • Spring Framework (15)
        • Spring (8)
        • JPA (5)
        • Spring Security (0)
      • Language (51)
        • Java (11)
        • Python (10)
        • JavaScript (5)
        • NUXT (2)
        • C C++ (15)
        • PHP (8)
      • DB (16)
        • MySQL (10)
        • Reids (3)
        • Memcached (2)
      • 개발 (3)
      • 프로젝트 (6)
      • Book (2)
      • PS (15)
        • 기타 (2)
        • 백준 (2)
        • 프로그래머스 (10)
      • 딥러닝 (8)
        • CUDA (0)
        • Pytorch (0)
        • 모델 (0)
        • 컴퓨터 비전 (4)
        • OpenCV (1)
      • 기타 (16)
        • 디자인패턴 (2)
        • UnrealEngine (8)
        • ubuntu (1)
        • node.js (1)
        • 블로그 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    C++
    pytorch
    NUXT
    언리얼엔진4
    php
    FPS
    클래스
    게임 개발
    Python
    memcached
    mscoco
    알고리즘
    C
    JS
    프로그래머스
    Unreal Engine
    MySQL
    CPP
    PS
    JavaScript
    파이썬
    게임
    redis
    웹
    select
    블루프린트
    자바
    딥러닝
    Unreal
    map
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
덴마크초코우유
[Spring] 낙관적 락 / 비관적 락 비교하기
상단으로

티스토리툴바