ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 충돌이 많을때 왜 낙관적 락을 쓰지 말라고 할까?
    카테고리 없음 2021. 9. 6. 00:00

    데이터베이스나 분산 시스템에서 동시에 여러 트랜잭션이 같은 데이터를 접근할 때 발생할 수 있는 충돌을 관리하기 위해,  동시성을 보장하기 위해 락을 사용한다. 그리고 락을 사용할때 흔히 들은 말은 "충돌이 많으면 비관적 락을 쓰는게 낫다" 이다. 이 같은 말을 들었을때 왜? 라는 의문이 들기보다는 교과서 암기처럼 숙지하고 넘어갔었는데 그 이유에 대해서 알아보려고 한다. 우선 낙관적락과 비관적락이 무엇인지에 대해서 알아보고 어떤 특징이 있는지 확인해보자.

     

    Optimistic Locking (낙관적 잠금)

    • Optimistic locking은 트랜잭션이 데이터를 읽을 때는 잠금을 걸지 않고, 데이터를 수정하고자 할 때 다른 트랜잭션이 해당 데이터를 변경했는지 확인하는 방식이다.
    • 일반적으로 version number 또는 timestamp와 같은 추가적인 필드를 이용한다. 데이터 갱신 시점에 이 필드의 값이 동일한지 확인하고, 동일할 경우에만 업데이트를 허용한다. 데이터를 수정하기 전에 다른 트랜잭션이 데이터를 수정했는지 확인하는데 만약 트랜잭션이 데이터를 수정하려고 할 때, 이전 버전과 현재 버전이 일치하면 데이터가 수정되고 트랜잭션이 성공하며 버전이 다르면 다른 트랜잭션이 데이터를 먼저 수정한 것이므로, 현재 트랜잭션은 실패하게 된다.

     

     

    Pessimistic Locking (비관적 잠금)

    • Pessimistic locking은 데이터를 읽는 시점에 바로 잠금을 걸어 다른 트랜잭션이 해당 데이터에 접근하지 못하게 하는 방식이다.
    • 비관적 잠금에서는 트랜잭션이 데이터를 읽을 때 바로 잠금을 걸어 다른 트랜잭션이 해당 데이터에 접근하지 못하게 하는데 이렇게 되면 다른 트랜잭션은 대기하게 된다. 즉, 먼저 잠금을 걸어 놓은 트랜잭션이 데이터를 다 처리하고, 잠금을 해제할 때까지 다른 트랜잭션은 기다려야 한다. 그 결과, 다른 트랜잭션은 실패하지 않고 대기하다가 자신의 차례가 되면 데이터를 수정할 수 있다.

    특징

    • 데이터 수정이 보장됨: 먼저 잠금을 얻은 트랜잭션이 작업을 완료할 때까지 다른 트랜잭션이 기다리기 때문에, 이미 잠금을 얻은 트랜잭션은 반드시 데이터를 수정할 수 있다.
    • 실패 대신 대기: 낙관적 잠금과는 달리, 비관적 잠금에서는 트랜잭션이 실패하는 대신, 잠금을 얻을 수 있을 때까지 기다린다.
    • 데드락 위험: 하지만 잠금을 사용하는 트랜잭션들이 서로 기다리는 상황(예: 트랜잭션 A가 데이터 X에 대해 잠금을 걸고, 동시에 트랜잭션 B가 데이터 Y에 대해 잠금을 걸고 있는 상황에서, A가 Y를, B가 X를 필요로 하는 경우)에서는 데드락 ( 교착 상태 ) 가 발생할 수 있다.

     

    비관적 잠금에서는 충돌이 발생하더라도 트랜잭션이 실패하지 않고 대기하는 방식으로 처리된다고 한다. 따라서 동일한 데이터에 접근하려는 다른 트랜잭션은 잠금을 해제할 때까지 기다리게 되는 것. 반면에, 낙관적 잠금에서는 충돌이 발생하면 트랜잭션이 실패하게 되어, 해당 트랜잭션을 다시 시도해야 하므로 불필요한 반복이 발생할 수 있다.

     

    결국, 비관적 잠금은 대기 시간을 감수하고서라도 데이터의 일관성과 충돌 관리를 보장하는 데 유리한 반면, 낙관적 잠금은 데드락을 피하면서 성능을 높이려는 환경에서 유리하다. 충돌이 많을 때는 비관적 잠금이 더 나은 선택이 될 수 있는 이유가 여기 있다. 수많은 요청으로 충돌이 많아지고 이에 수많은 실패로 재시도를 하는것보다 대기를 하는게 나은 경우이다.

     

    대기와 실패의 상황 비교

     

    1. 대기 (비관적 잠금)

    • 예시 상황:
      • 두 명의 사용자가 동일한 상품을 동시에 구매하려고 시도한다고 가정해보자.
      • 첫 번째 사용자가 트랜잭션을 시작하고 상품 재고에 잠금을 건다.
      • 이때 두 번째 사용자는 동일한 상품을 구매하려고 시도하지만, 이미 첫 번째 사용자가 잠금을 걸어 놓았으므로 잠금이 해제될 때까지 대기한다.
      • 첫 번째 사용자가 작업을 완료하고 잠금을 해제하면, 두 번째 사용자는 대기 상태에서 깨어나고, 자신의 작업을 시작할 수 있다.
    • 결과:
      • 두 번째 사용자는 대기 시간이 길어질 수 있지만, 트랜잭션이 실패하지 않고 처리된다.
      • 여기서 "대기"는 시스템이 데이터를 안전하게 처리하기 위해 걸리는 시간으로 이해할 수 있다.

    2. 실패 (낙관적 잠금)

    • 예시 상황:
      • 똑같은 상황에서 두 번째 사용자가 잠금을 대기하지 않고, 낙관적 잠금 방식으로 트랜잭션을 수행한다.
      • 첫 번째 사용자가 트랜잭션을 완료하고 나면, 두 번째 사용자가 데이터를 수정하려고 할 때, 이미 변경된 것을 감지하고 트랜잭션이 실패하게 된다.
      • 두 번째 사용자는 실패한 트랜잭션을 다시 시도해야 한다.
    • 결과:
      • 두 번째 사용자는 트랜잭션이 실패하게 되어, 다시 시도해야 하는 불편함이 있다.
      • 이 반복적인 실패가 많아질수록, 사용자는 더 오랜 시간 동안 작업을 완료하지 못할 수 있다.

     

    충돌이 많은 상황에서는 낙관적 잠금을 사용할 경우, 트랜잭션이 자주 실패하게 된다. 이로 인해 사용자가 반복적으로 작업을 시도해야 하고, 이는 사용자 경험에 있어 불편함과 불안정성을 초래할 수 있다. 비즈니스 상황에 따라 이러한 반복적인 실패는 특히 중요한 데이터의 일관성이나 신뢰성이 필요한 경우, 심각한 문제로 이어질 수 있다. 예를 들어, 금융 거래, 재고 관리, 예약 시스템 등에서 이러한 실패는 사용자에게 큰 불편을 주고, 시스템 신뢰도를 낮출 수 있다.

     

     

    따라서, 충돌이 많이 발생하는 상황에서는 잠금이 걸리는 동안 다른 트랜잭션이 대기하도록 하는 비관적 잠금이 더 적합하다고 할 수 있을 것 같다. 비관적 잠금을 사용하면 충돌이 발생하더라도 트랜잭션이 실패하지 않고 안전하게 완료될 수 있기 때문에, 데이터의 일관성을 유지하고, 사용자에게 안정적인 경험을 제공할 수 있다. 이를 요약하면, 충돌이 빈번한 환경에서는 비관적 잠금이 더 적합한 선택이라고 볼 수 있는 것.

     

     

Designed by Tistory.