DB 동시성 제어

Park sang woo·2024년 3월 17일

12주차 DataBase

목록 보기
3/5

📓 동시성 제어

멀티 유저 환경에서 DB 자원에 대한 접근 보장.
다중 요청들이 같은 데이터에, 같은 시간에 요청되어도 DB의 Data 무결성이 위배되지 않게 하는 제어다.

  • Locking : 트랜잭션이 데이터에 잠금(Lock) 을 설정하면 다른 트랜잭션은 해당 데이터에 대해 잠금이 해제(UnLock)될 때까지 접근/수정/삭제 불가.

  • 타임 스탬프 기법 : 시스템에서 생성하는 고유 식별자인 타임 스탬프를 트랜잭션에 부여함으로써 트랜잭션 간의 접근 순서를 미리 정함.

  • 적합성 검증(낙관적) : 먼저 트랜잭션을 수행하고 종료할 때 적합성을 검증하여 데이터베이스에 최종 반영.






📓 낙관적 락

모든 사용자가 동시에 거래를 입력할 수 있도록 하는 거래 잠금 방식.
그러나 여러 사용자가 동시에 트랜잭션을 커밋하는 충돌 상황에서 한 사용자가 트랜잭션을 성공적으로 커밋하면 충돌하는 다른 모든 요청이 거부.
주어진 예에서는 사용자 1과 사용자 2가 모두 동일한 레코드에 대한 트랜잭션 요청을 동시에 보내는 것을 관찰합니다. 그러나 사용자 1의 트랜잭션이 반대편에서 성공적으로 업데이트되는 동안 사용자 2의 커밋된 트랜잭션은 거부됩니다. 따라서 트랜잭션을 재시도하려면 사용자 2는 먼저 현재 데이터를 읽은 다음 해당 정보를 기반으로 새 트랜잭션을 생성해야 합니다.






📓 비관적 락

데이터베이스의 레코드를 동시에 업데이트하면서 두 명 이상의 사용자 간에 충돌이 발생할 경우 트랜잭션을 제어하는 잠금 방식. 이 경우 한 사람만 데이터를 업데이트할 수 있지만 다른 모든 사용자의 경우 데이터베이스에 액세스할 수 있지만 수정할 수는 없다.


위의 예에는 User 1과 User 2라는 두 명의 사용자가 있습니다. User 1은 트랜잭션 요청을 시작하고 즉시 성공적으로 업데이트. 한편, 사용자 2는 레코드를 읽기 위해 데이터베이스에 액세스하는 것으로 제한됩니다. 사용자 1의 거래가 완료된 후 사용자 2는 자신의 거래를 진행할 수 있는 권한을 얻는다.

🏷️ 낙관적/비관적 락 (조금 더 쉬운 이해를 위해.)

비관적 락 = 분명히 충돌날 수 있어. 먼저 체크하자
선락후사 => 먼저 Lock을 통해 작업 전에 잠그고, 작업 후에 Lock을 풀어 사용.

  • 읽기/쓰기 중 쓰기 비중이 높을 때 사용.
  • 데이터 무결성 보장 수준이 높으나 동시성 떨어짐. + 데드락 발생 위험
  • 가능하도록 제어하는 방법이다.


낙관적 락 = 에이 설마 충돌 나겠어? 그냥 먼저 해
충돌에 대해 생각하지 않고 먼저 Lock없이 수행된 시점 혹은 버전만을 표기해놓고 모든 것을 수행. (성능 좋음)
선사후락 => 선 작업하고 후 버전 체크. Lock 없이 먼저 수행하고난뒤에, 명령어의 끝에 꼭 버전체크.

  • 읽기/쓰기 중 읽기 비중이 높을 때 사용.
  • OptimisticLockException : 쓰기 시 충돌(버전 불일치) 나면 작업한 내용을 직접 롤백 필요.
  • 동시성 좋으나 데이터 무결성 보장 수준이 낮고 Versioning, Exception 처리에 대한 추가 개발 필요.


1. 01, 02 가 동시에 예금 0을 읽음.
2. 업데이트 함
3. 처음에 읽은 시점과 쓰고자 하는 시점을 비교
4. commit 시점에 Exception 발생 (Optimistic Lock Exception)



🏷️ 데드락 발생

교착 상태라고 하고 두 트랜잭션이 각각 Lock을 설정하고 서로의 Lock에 접근하여 값을 얻어오려 할 때 이미 각 트랜잭션에 의해 Lock이 설정되어 있기 때문에 트랜잭션이 영원히 처리가 되지 않게 되는 상태.

  1. @GeneratedValue 를 위한 Connection 시 Thread 부족에 따른 데드락

  2. 2개의 트랜잭션이 각각 R1 과 R2 를 (1) 순서, (2) 역순으로 업데이트 시 데드락 발생

  • Shared Lock (공유, 읽기 잠금, s-lock) : 다중 s-lock(읽기) 가능 / x-lock(쓰기) 접근 불가
  • Exclusive Lock (베타, 쓰기 잠금, x-lock) : 모든 lock (s-lock, x-lock) 접근 불가





🏷️ 예시

카페 화장실 사용 방식의 차이로 비유하면 이해가 쉽다. (가정: 화장실 변기가 하나라 한 사람만 사용 가능)

  • 카페 문 옆에 1개의 화장실 전자키를 두고, 화장실 갈때마다 키를 가져가는건 Pessimistic Lock
    • 카페에서 화장실 가려고 일어나 문 앞에 서는 순간, 키가 없으면 문앞에서 기다린다.
    • 화장실 전자키 = 데이터베이스 빌트인 Lock ← Pessimistic Lock
      • 그래서, RDBMS(관계형 데이터베이스) 에서 많이 사용하는 방식이다.
  • 화장실 전자키 없이 그냥 화장실문 앞에서 똑똑똑을 통해 있는지 확인하는건 Optimistic Lock
    • 카페에서 화장실 가고싶으면, 그냥 바로 화장실로 가면 된다. 갔는데 문이 잠겨있으면 기다린다.
    • 화장실문 똑똑똑 = 소프트웨어적 Lock (누구나 다 화장실 접근가능) ← Optimistic Lock
      • 그래서, NoSQL(비관계형 데이터베이스) 에서 많이 사용하는 방식이다.





📓 NoSQL에는 Lock이 없다?

NoSQL은 분산 DB 시스템이다. 위 예시처럼 화장실이 1개라고 한다면 NoSQL은 수평적 확장을 중시하여 노드를 추가하면 성능을 개선할 수 있는데 Lock을 사용하면 분산 환경에서의 데이터 동기화를 위해 많은 오버헤드가 발생할 수 있다.
Lock 기반의 동시성 제어로 성능 저하를 가져옴.






📓 MVCC (다중 버전 동시성 제어)

동시 접근을 허용하는 DB에서 동시성을 제어하기 위해 사용하는 방법. MVCC에서 데이터에 접근하는 사용자는 접근한 시점에 데이터베이스의 Snapshot을 읽는다.
이 snapshot 데이터에 대한 변경이 완료(commit)될 때 까지의 변경사항은 다른 데이터베이스 사용자가 볼 수 없다.

이후에 사용자가 업데이트 하면 이전의 데이터를 덮어 씌우는 것이 아니라 새로운 버전의 데이터를 UNDO 영역에 생성한다.
대신 이전 버전의 데이터와 비교해서 변경된 내용을 기록한다.


🏷️ 동시성 제어 기법 종류 정리

기법 이름장점단점
Locking 기법❇︎ 데이터 오류 가능성 사전에 예방
❇︎ 구현하기 쉬움
❇︎ Lock 대기 시간 -> 동시성 저하
❇︎ 교착 상태 발생 가능성 존재
TimeStamp❇︎ 교착 상태 발생 가능성 없음
❇︎ 트랜잭션 대기 시간 없음
❇︎ 롤백 발생 확률 높음
적합성 검증❇︎ 동시 처리 능력 증가
❇︎ 트랜잭션 대기 시간 없음
❇︎ 장기 트랜잭션 철회 시 자원 낭비
MVCC❇︎ 트랜잭션 대기 시간 없음
❇︎ 다른 트랜잭션이 해당 데이터를 수정해도 영향 받지 않음
❇︎ 사용하지 않는 데이터를 정리하는 시스템이 필요
❇︎ 데이터 버전의 충돌이 일어날 수 있음
❇︎ Undo 블록, I/O 등의 부가적인 오버헤드 발생





Reference

Reference

🔗 https://stackoverflow.com/questions/129329/optimistic-vs-pessimistic-locking/129397#129397
🔗 https://www.educative.io/answers/whats-the-difference-between-optimistic-and-pessimistic-locking
🔗 https://velog.io/@choidongkuen/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%A0%9C%EC%96%B4Concurrency-Controll - 동시성 제어
🔗 https://mangkyu.tistory.com/53

profile
일상의 인연에 감사하라. 기적은 의외로 가까운 곳에 있을지도 모른다.

0개의 댓글