11/28

졸용·2025년 11월 28일

TIL

목록 보기
124/144

🔹 DB Lock(락)이란?

DB 락은 MSA, JPA, 트랜잭션 동시성 문제에서 자주 터지는 주제라 중요하다.

여러 트랜잭션이 동일한 데이터에 동시에 접근할 때,
데이터의 정합성(Consistency)을 지키기 위해 잠금(Lock)을 거는 메커니즘을 말한다.

즉, 충돌 나는 동시 접근을 막기 위한 ‘문 잠그기’라고 생각하면 된다.



🔹 Lock의 종류

DB마다 종류가 다양하지만, 일단은 **실무에서 가장 중요한 세 가지만 중심으로 알아보았다.

🔸 Shared Lock (S Lock, 읽기 락)

  • 다른 트랜잭션이 읽는 것을 허용
  • 하지만 쓰는 것(UPDATE/DELETE) 은 불가
  • 주로 SELECT ... FOR SHARE 또는 MySQL의 LOCK IN SHARE MODE 형태

특징:

  • 여러 트랜잭션이 동시에 읽기 가능
  • 쓰기 트랜잭션은 차단됨

🔸 Exclusive Lock (X Lock, 쓰기 락)

  • 데이터를 수정(UPDATE/DELETE) 하려는 트랜잭션이 거는 락

  • 걸리는 순간:

    • 다른 트랜잭션의 읽기/쓰기 모두 막힘

특징:

  • 가장 강함
  • 충돌이 가장 자주 발생
  • MySQL: SELECT ... FOR UPDATE

🔸 Row Lock

  • 테이블 전체가 아니라 특정 로우(row)만 잠금
    → 동시성 우수, 가장 이상적인 경우

🔸 Table Lock

  • 테이블 전체 잠김
  • 인덱스가 없거나, 조건이 테이블 대부분 스캔 시 자동으로 Table Lock 발생 가능


🔹 DB Lock이 걸리는 순간

트랜잭션이 다음을 실행할 때 lock이 걸린다:

🔸 SELECT … FOR UPDATE

→ Row Lock
→ “해당 로우를 쓸 예정이니 잠깐 아무도 건드리지 마”

🔸 UPDATE / DELETE

→ 자동으로 Exclusive Lock 걸림

🔸 INSERT

→ 삽입되는 PK row에 lock 걸림
→ 단, 중복 체크 위해 “gap lock”이 생길 수 있음(MySQL InnoDB)



🔹 Deadlock(데드락)이란?

서로 락을 잡은 상태에서 상대가 가진 락을 기다리며 영원히 끝나지 않는 상태.

예시:

트랜잭션 A트랜잭션 B
row1 lockrow2 lock
row2 lock 대기row1 lock 대기

→ 서로 상대방이 풀기를 기다림 → Deadlock

  • DB는 보통 한쪽 트랜잭션을 자동으로 KILL해서 해결해줌
    Deadlock found when trying to get lock; try restarting transaction 오류


🔹 Lock 대기 시간이 지나면?

DB는 트랜잭션을 Lock wait timeout으로 실패시킨다.

MySQL 기본 값:

innodb_lock_wait_timeout = 50초

장시간 락 때문에 장애가 발생하는 것을 막기 위함.



🔹 Spring/JPA에서 자주 발생하는 Lock 문제

🔸 JPA의 기본 SELECT는 Lock 없음

→ 따라서 동시성 이슈 발생 가능 (Lost Update)


🔸 버전 락(Optimistic Lock)으로 해결

@Version
private Long version;

→ 충돌 시 예외 발생 → 재시도 로직 사용


🔸 비관적 락(Pessimistic Lock)

@Lock(PESSIMISTIC_WRITE)
@Query("select u from User u where u.id = :id")
User findByIdForUpdate(Long id);

→ 실제 DB의 SELECT FOR UPDATE 실행
→ 동시 수정 방지 확실



🔹 언제 어떤 Lock을 써야 할까?

상황추천 락
재고 감소, 은행 계좌 이체비관적 락(PESSIMISTIC_WRITE)
동시에 수정될 가능성이 낮음낙관적 락(Optimistic Lock)
목록 조회, 읽기 위주Shared Lock(없음도 가능)
주문번호 고유값 생성 등Row Lock + Unique Index


🔹 MSA에서 Lock은 어떻게 다루나?

서비스가 여러 개로 나뉘면, DB 로우 기반 락만으로는 해결 안 된다. 그래서:

🔸 분산 락 사용 (Redis 기반 – 레디슨 Redisson)

  • 주문 생성, 재고 감소 같은 “전역 동시성 제어”에 사용
RLock lock = redissonClient.getLock("stock:" + productId);
try {
    if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
        // 재고 감소
    }
} finally {
    lock.unlock();
}


🔹 핵심 요약

  • Lock은 읽기 Lock(S), 쓰기 Lock(X)으로 나뉜다.
  • UPDATE/DELETE는 자동으로 X Lock 발생
  • 동시 수정 시 Lost Update 방지를 위해 Optimistic or Pessimistic Lock 사용
  • Deadlock은 서로 락을 기다리는 교착 상태
  • MSA에서는 Redis 기반 분산 락(Redisson)이 필수적으로 등장한다.
profile
꾸준한 공부만이 답이다

0개의 댓글