pile·
백엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

데드락을 해결하려다, 락을 줄이게 된 이야기

여기어때 유저혜택개발팀에서 신규 유저 리워드 이벤트 시스템 개발 중 MySQL InnoDB 데드락을 추적하고, 결국 락 자체를 줄이는 방향으로 해결한 과정을 다룬다. Kafka 기반 비동기 이벤트 처리와 동시성 제어가 얽힌 실전 사례다.

핵심 포인트
  • INSERT IGNORE는 중복 키 확인 시 S-Lock을 잡고, 이어서 FOR UPDATE가 X-Lock 승격을 요청하면서 두 트랜잭션이 순환 대기에 빠졌다
  • ON DUPLICATE KEY UPDATE는 X-Lock을 직접 잡아 승격 문제가 없었으나 매번 불필요한 쓰기가 발생했다
  • 두 번째 데드락은 이벤트 경로마다 락 획득 순서가 달라 ABBA 순환 대기가 발생한 패턴이었다
  • 근본 원인은 rookie_reward 테이블의 카운터 필드 — 모든 이벤트가 같은 Hot Row를 수정해야 했다
  • 카운터를 rookie_reward_step 집계로 대체하자 FOR UPDATE 자체가 불필요해졌다
  • REQUIRES_NEW 별도 트랜잭션으로 생성 시 잡히는 S-Lock의 수명을 메시지 전체가 아닌 생성 단위로 제한했다
상세 정리
  • 시스템 구조: 신규 유저 구매→이용완료→포인트 지급 이벤트가 Kafka At-Least-Once로 처리되며, 순서 보장 불가 + 중복 가능 전제로 설계 필요
  • 1차 접근: rookie_reward(유저 단위 행)를 SELECT FOR UPDATE로 잠가 순차 처리 시도, 단건은 정상 작동
  • INSERT IGNORE 전환 시도: ON DUPLICATE KEY UPDATE의 불필요한 UPDATE를 없애려 변경했더니 데드락 발생
  • 1번째 데드락 원인: INSERT IGNORE가 중복 확인 시 S-Lock 보유, 같은 트랜잭션 내 FOR UPDATE가 X-Lock 승격 요청 → 두 트랜잭션이 S-Lock 보유한 채 X-Lock 대기 → 순환 대기
  • InnoDB 락 특성: S-Lock끼리는 호환되므로 두 트랜잭션 모두 같은 row에 S-Lock 보유 가능, 그 뒤 X-Lock 승격 요청에서 교착
  • 2번째 데드락 원인: 레저티켓 체크아웃 경로가 rookie_reward_step → rookie_reward 순서로 락 획득, 나머지는 반대 순서 → ABBA 패턴
  • ABBA 해결: 팀 전체 "rookie_reward → rookie_reward_step" 순서로 통일, EntityManager.refresh로 JPA 1차 캐시 최신성 확보
  • 근본 재검토: orderCounter/checkoutCounter/rewardCounter가 모든 이벤트를 Hot Row로 수렴시킨 설계 결함 발견
  • 카운터 제거: step 테이블 집계 쿼리로 대체, 대부분 이벤트에서 rookie_reward UPDATE 불필요 → FOR UPDATE 불필요
  • REQUIRES_NEW 트랜잭션: 생성 S-Lock의 수명을 메시지 전체 처리 시간이 아닌 생성 단위로 제한 + REPEATABLE READ 스냅샷 문제 해결
  • 대안 검토: Redis 분산 락(락↔트랜잭션 경계 불일치 문제), 낙관적 락(충돌 빈도 높아 재시도 비용 큼) 모두 기각
  • 최종 결론: "어떻게 락을 잘 걸까"가 아니라 "이 락이 정말 필요한가"를 먼저 물어야 한다
왜 읽나MySQL InnoDB 데드락을 디버깅하고 락 자체를 없애 해결하는 과정을 따라가는 백엔드·데이터 엔지니어에게 실전 레퍼런스.
여기어때 (GC컴퍼니)
여기어때 (GC컴퍼니) 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·twilio-engTwilio Engineering·

    Programmable Messaging에서 Verify API로 마이그레이션하기

    Twilio의 Programmable Messaging API로 자체 OTP 솔루션을 운영하던 서비스가 Verify API로 전환하는 방법을 코드 예시와 함께 설명한다. Verify는 OTP 전송·검증을 위한 전용 API로, 전화번호 구매, 토큰 생성, DB 저장·만료 관리를 내부에서 처리해 개발자가 직접 구현할 코드를 크게 줄인다.

    요약 이어보기
    #authentication#twilio#sms+2
  2. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 2부

    포스타입 백엔드 엔지니어가 벡터 기반 개인화 추천 시스템을 실제 운영하며 맞닥뜨린 성능 장애와 용량 문제를 해결한 과정을 담은 2부다. 수백만 개의 벡터 KNN 검색이 피크 시간대에 전체 Elasticsearch 검색 성능을 흔드는 문제부터 클러스터 OOM 사태까지, 쿼리 최적화와 인프라 분리 두 가지 경로로 근본 해결에 이른다.

    요약 이어보기
    #elasticsearch#vector-search#recommendation-system+2
  3. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 1부

    포스타입이 태그 기반 추천의 한계를 극복하고 벡터 임베딩 기반 개인화 추천 시스템을 구축한 과정을 담은 1부다. 유사한 콘텐츠가 다른 용어를 쓰거나 동일한 태그가 전혀 다른 톤의 콘텐츠를 가리키는 문제를 임베딩 벡터로 해결하고, OpenSearch의 HNSW ANN 검색으로 수백만 벡터를 실시간 검색하는 시스템을 구축해 구매율 15% 향상을 달성했다.

    요약 이어보기
    #opensearch#vector-search#recommendation-system+2