# 낙관적(Optimistic) 락과 비관적(Pessimisitc)락

### 낙관적(Optimistic) 락과 비관적(Pessimisitc)락 <a href="#optimistic-pessimisitc" id="optimistic-pessimisitc"></a>

> 두 락의 차이를 알아봅니다.

***

### Goal <a href="#goal" id="goal"></a>

* **낙관적 락**과 **비관적 락**에 대해서 알아봅니다.
* 비관적 락에 사용되는 **공유락(Shared Lock)** 과 **베타락(Exclusive Lock)**&#xC5D0; 대해서 알아봅니다.
* 언제 어떤 락을 써야할지에 대해서 고민해봅니다.

***

### 비관적 락 <a href="#undefined" id="undefined"></a>

> 자원 요청에 따른 동시성문제가 발생할것이라고 예상하고 **락을 걸어버리는** 방법론입니다.

* 트랜잭션의 충돌이 발생한다고 가정합니다.
* 하나의 트랜잭션이 자원에 접근시 락을 걸고, 다른 트랜잭션이 접근하지 못하게 합니다.
* 데이터베이스에서 **Shared Lock(공유, 읽기 잠금)** 이나 **Exclusive Lock(배타, 쓰기 잠금)** 을 겁니다.
* **Shared Lock** 의 경우, 다른 트랜잭션에서 **읽기**만 가능합니다. 또한 **Exclusive lock** 적용이 불가능합니다. (읽는동안 변경하는것을 막기 위해)
* **Exclusive lock** 의 경우. 다른 트랜잭션에서 **읽기, 쓰기**가 둘다 **불가능**합니다. 또한 **Shared, Exclusive Lock** 적용이 추가적으로 불가능합니다. (쓰는동안 읽거나, 다른 쓰기가 오는것을 막기위해)

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>-- Shared Lock이 걸린경우
1번 트랜잭션: 1번 유저의 닉네임을 읽음
2번 트랜잭션: 1번 유저의 닉네임을 jys로 변경함

\-- 유저테이블에 1번 유저 unluckyjung 이라는 닉네임이 있다고 가정합니다.

1번 트랜잭션이 unluckyjung 데이터를 먼저 읽고 있을때 2번 트랜잭션이 접근한다면
1번 트랜잭션이 작업하는동안, 2번 트랜잭션은 읽기는 가능하나 jys 으로 변경하진 못합니다. </code></pre></td></tr></tbody></table>

#### 장점 <a href="#undefined" id="undefined"></a>

* **충돌이 자주 발생하는 환경**에 대해서는 롤백의 횟수를 줄일 수 있으므로 성능에서 유리합니다.
* 데이터 무결성을 보장하는 수준이 매우 높습니다.

#### 단점 <a href="#undefined" id="undefined"></a>

* 데이터 자체에 락을 걸어버리므로 **동시성이 떨어져** 성능 손해를 많이 보게 됩니다. 특히 읽기가 많이 이루어지는 데이터베이스의 경우에는 손해가 더 두드러집니다.
* 서로 자원이 필요한 경우에, 락이 걸려있으므로 **데드락**이 일어날 가능성이 있습니다.

***

### 낙관적 락 <a href="#undefined" id="undefined"></a>

> 자원에 락을 걸어서 선점하지말고, 동시성 문제가 발생하면 **그때 가서 처리** 하자는 방법론입니다.

* 트랜잭션의 충돌이 발생하지 않을것이라고 기대합니다.
* 일단 충돌이 나는것을 막지 않고, 충돌이 난것을 감지하면 그때 처리합니다.
* 일반적으로 **version** 의 상태를 보고 충돌을 확인하며, 충돌이 확인된경우 롤백을 진행시킵니다. (hashcode나 timestamp를 이용해서 충돌을 확인할 수 도 있습니다.)
* DB단에서 동시성을 처리하는것이 아닌, **어플리케이션단에서 처리** 합니다.

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>1번 요청: 1번 유저의 닉네임을 jung yoonsung로 변경함
2번 요청: 1번 유저의 닉네임을 jys로 변경함

\-- 유저테이블에 1번 유저 unluckyjung 이라는 닉네임이 있다고 가정합니다.
\-- 해당 유저 데이터의 초기버전은 1입니다.
\-- 가장 먼저 업데이트 된것을 적용하는 전략을 선택합니다.

1번 요청: 1번 버전의 1번 유저에게 jung yoonsung으로 변경하고 2번 버전으로 업데이트를 쏩니다.
2번 요청: 1번 버전의 1번 유저에게 jys으로 변경하고 2번 버전으로 업데이트를 쏩니다.

\-- 만약 2번 요청이 먼저 완료되는경우
유저이름은 jys로 바뀌고 2번 버전으로 저장됩니다.
1번 요청에는 버전1을 기반으로 요청을 했는데 2번 요청이 완료됨으로 인해 버전이 2번으로 바뀌어, 1번 버전이 없어졌으므로 업데이트에 실패합니다. </code></pre></td></tr></tbody></table>

* 이때 여러 작업이 묶인 트랜잭션으로 요청이 간 경우가 실패한경우, **개발자가 직접 롤백 처리** 를 해주어야합니다.

#### 장점 <a href="#id-1" id="id-1"></a>

* 충돌이 안난다는 가정하에, **동시 요청**에 대해서 처리 성능이 좋습니다.

#### 단점 <a href="#id-1" id="id-1"></a>

* 잦은 충돌이 일어나는경우 **롤백처리**에 대한 비용이 많이 들어 오히려 성능에서 손해를 볼 수 있습니다.
* 롤백 처리를 **구현**하는게 복잡할 수 있습니다.

***

### Conclusion <a href="#conclusion" id="conclusion"></a>

* **비관적락** 은 데이터의 무결성이 중요하고, 충돌이 많이 발생하여 잦은 롤백으로 인한 효율성 문제가 발생하는것이 예상되는 시나리오에서좋습니다.
* **낙관적락** 은 실제로 데이터 충돌이 자주 일어나지 않을것이라고 예상되는 시나리오에서 좋습니다.
* 개인적인 생각으로는 데이터베이스 설계 단계에서 충돌여부가 발생하는지 어느정도 추측은 가능하나 확실치 않으므로, **애매한경우 비관적락** 을 걸어두고 서비스 도중 실제로 **충돌이 자주 일어나지 않는것이 확인** 된 경우에 **낙관적락** 을 사용하는것이 좋지 않을까 생각합니다.

***

### Reference <a href="#reference" id="reference"></a>

* <https://stackoverflow.com/questions/129329/optimistic-vs-pessimistic-locking>
* <https://stackoverflow.com/questions/11837428/whats-the-difference-between-an-exclusive-lock-and-a-shared-lock>
* <https://jeong-pro.tistory.com/94>
* <https://sabarada.tistory.com/121>

<br>
