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

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

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


Goal

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

비관적 락

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

  • 트랜잭션의 충돌이 발생한다고 가정합니다.
  • 하나의 트랜잭션이 자원에 접근시 락을 걸고, 다른 트랜잭션이 접근하지 못하게 합니다.
  • 데이터베이스에서 Shared Lock(공유, 읽기 잠금) 이나 Exclusive Lock(배타, 쓰기 잠금) 을 겁니다.
  • Shared Lock 의 경우, 다른 트랜잭션에서 읽기만 가능합니다. 또한 Exclusive lock 적용이 불가능합니다. (읽는동안 변경하는것을 막기 위해)
  • Exclusive lock 의 경우. 다른 트랜잭션에서 읽기, 쓰기가 둘다 불가능합니다. 또한 Shared, Exclusive Lock 적용이 추가적으로 불가능합니다. (쓰는동안 읽거나, 다른 쓰기가 오는것을 막기위해)
1
2
3
4
5
6
7
8
-- Shared Lock이 걸린경우
1번 트랜잭션: 1번 유저의 닉네임을 읽음
2번 트랜잭션: 1번 유저의 닉네임을 jys로 변경함

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

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

장점

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

단점

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

낙관적 락

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

  • 트랜잭션의 충돌이 발생하지 않을것이라고 기대합니다.
  • 일단 충돌이 나는것을 막지 않고, 충돌이 난것을 감지하면 그때 처리합니다.
  • 일반적으로 version 의 상태를 보고 충돌을 확인하며, 충돌이 확인된경우 롤백을 진행시킵니다. (hashcode나 timestamp를 이용해서 충돌을 확인할 수 도 있습니다.)
  • DB단에서 동시성을 처리하는것이 아닌, 어플리케이션단에서 처리 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
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번 버전이 없어졌으므로 업데이트에 실패합니다.
  • 이때 여러 작업이 묶인 트랜잭션으로 요청이 간 경우가 실패한경우, 개발자가 직접 롤백 처리 를 해주어야합니다.

장점

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

단점

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

Conclusion

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

Reference

  • 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