낙관적 락 (Optimistic Lock)

Created
May 25, 2025
Created by
D
DaEun Kim
Tags
system-design
Property

비관적 락(Pessimistic Lock)은 여기에 소개한 것과 같이 트랜잭션 내에서 select ~ for update 와 같은 구문을 통해 명시적으로 락을 생성하여 동시성을 제어하는 방법이다.

비관적 락의 단점은 동일한 레코드에 접근하는 트랜잭션이 많아질수록 쓰루풋에 영향을 주고 데드락(deadlock)이 발생할 여지가 크다는 것이다.

낙관적 락(Optimistic Lock)은 여러 개의 트랜잭션들이 같은 레코드를 동시에 갱신 시도하는 것을 허용하면서 동시성을 제어한다.

image

위 그림에서는 타임스탬프 컬럼으로 동시성을 제어하지만 integer 타입의 versioning number 컬럼으로 제어하기도 한다.

아래 코드는 Django ORM 과 order 테이블을 예시로 들어서 낙관적 락을 작성한 것이다.

 from django.db import transaction
 
 
 @transaction.atomic
 def update_order_status(order_id, new_status):
    try:
        # Order 조회
        order = Order.objects.get(id=order_id)
      
        # 현재 버전 저장
        current_version = order.version
        order.status = new_status
        order.version += 1

        # 낙관적 락: WHERE 조건에 버전 추가
        result = Order.objects.filter(
            id=order_id,
            version=current_version
        ).update(
	          status=new_status,
	          version=current_vesion + 1
        )

        # 업데이트가 성공적으로 수행되었는지 확인
        if result == 0:
            raise VersionMismatchError(...)

위의 예시에서 VersionMismatchError 예외가 발생하면 상태 갱신을 요청했던 클라이언트에게 상태 갱신이 실패했다는 메세지를 적절하게 제공해야 할 것이다.

낙관적 락은 비관적 락에 비해 트랜잭션이 빠르게 처리될 수 있다는 장점이 있지만 단점도 존재한다.

  1. 클라이언트가 레코드 갱신 실패를 반복적으로 경험할 수 있다. 특히 클라이언트가 엔드 유저라면 UX에 악영향을 준다.
  2. 동일한 레코드에 대해 경쟁이 매우 심하다면 나중에 생성된 트랜잭션일수록 대기시간이 길어질 수 있다. (update 쿼리는 exclusive lock 획득을 시도하고 트랜잭션은 exclusive lock 을 획득할 때까지 대기하기 때문)

참고도서