-
동시성 제어
동시성 다중 사용자 환경에서 동시에 여러 트랜잭션이 수행될 때 데이터베이스의 무결성 및 일관성을 유지 하고 트랜잭션의 직렬화 수행을 보장 하도록 트랜잭션 간의 데이터 접근을 제어하는 것을 말하며, 다중 사용자 환경을 지원하는 DBMS의 경우에는 반드시 동시성 제어(병행제어)가 지원되어야 한다.
동시성 제어가 이루어 지지 않는다면 ?
동시성 제어가 이루어 지지 않아 데이터 베이스의 직렬성이 결여될 경우 다음의 문제점이 발생할 수 있다.
문제점 설명 갱신손실 (Lost Update) - 두 개 이상의 트랜잭션이 한 개의 데이터를 동시에 갱신(Update)시 발생
- 하나의 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로 갱신이 무효화되는 경우
- 트랜잭션 종료 이전에 다른 트랜잭션이 갱신을 수행하는 경우
- 마지막 커밋만 인정, 최초커밋만 인정, 충돌하는 갱신 내용 병합등의 처리방법현황파악오류 (Dirty Read) - 읽기 작업을 수행하는 트랜잭션이 쓰기 작업 중인 다른 트랜잭션의 중간 데이터를 읽는 경우 발생
- 트랜잭션 중간 수행 결과를 다른 트랜잭션이 참조할 경우
- 쓰기 작업 중인 트랜잭션이 Rollback되는 경우 읽기 작업을 한 트랜잭션은 무효화 된 데이터를 읽어 잘못된 결과를 도출모순성 (Inconsistency) - 둘 이상의 트랜잭션이 동시에 수행될 때 발생
- 데이터 베이스가 상호간의 간섭으로 인해 일관성 없는 상태로 변질된 경우
- 둘 이상의 트랜잭션이 쓰기 작업을 하는 동안 다른 트랜잭션이 하나는 갱신되기 전, 다른 하나는 갱신된 후 값을 읽어 데이터가 불일치 하는 경우연쇄복귀 (Cascading Rollback) - 둘 이상의 트랜잭션 수행 중 실패한 트랜잭션에 의해 다른 트랜잭션이 영향받을 때 발생
- 쓰기작업을 하는 트랜잭션이 실패하여 Rollback하는 과정에서 다른 트랜잭션이 데이터를 읽었을 경우동시성 제어의 방법
제어 기법 종류 방법 장점 단점 Locking - 공유락 : 읽기 O, 쓰기 X
- 배타락 : 읽기 X, 쓰기 X- 데이터 오류 가능성 예방
- 간단한 알고리즘- Lock 대기시간 발생
- 데드락 발생2 Phase
Locking- 확장단계 : lock O, unlock X
- 수축단계 : lock X, unlock OTimestamp
Ordering- System Clock 또는 Logical Counter를 이용하여 들어오는 순서대로 순서 부여 - 데드락 발생 없음
- 트랜잭션 대기시간 없음- 높은 Rollback 발생 확률
- Cascading Rollback 가능Validation - 트랜잭션 종료 시 일괄적 검사 - 동시 처리 능력 증가
- 트랜잭션 대기시간 없음- 장기 트랜잭션 철회 시 자원 낭비 MVCC - 타임스탬프와 데이터의 여러 버전 타임스탬프를 비교하여 직렬 가능성이 보장되는 버전 선택 - 최근의 데이터 값을 선택
- 동시성, 일관성 동시 해결- Undo 블록 I/O에 따른 오버헤드 발생 -
- 데이터 수정 즉시 트랜잭션 충돌을 감지할 수 있다.
- 롤백을 개발자가 일일이 하는 것이 힘든 경우, 충돌이 일어났을 때 롤백 비용이 많이 드는 경우, 주문 시에 쿠폰 사용, 알림 제공, 주문서 작성 등의 여러 기능이 한 트랜잭션에 묶여 있는 경우에 적합하다.
- Locking
- 트랜잭션들의 동일한 데이터 항목에 대한 병행 접근을 제한하는 것
- 비관적인 락 (Pessimistic Lock)
- 데이터 베이스 단위의 락
- 데이터 수정 즉시 트랜잭션 충돌을 감지 가능
- 롤백을 개발자가 일일이 하는 것이 힘든 경우, 충돌이 일어났을 때 롤백 비용이 많이 드는 경우, 주문 시에 쿠폰 사용, 알림 제공, 주문서 작성 등의 여러 기능이 한 트랜잭션에 묶여 있는 경우에 적합
- 공유락 (LS, Shared Lock)
- 사용중인 데이터에 대해서 다른 트랜잭션이 읽기 O, 쓰기 X
- 읽기 작업 끼리는 서로 영향을 주지 않으므로 또 다른 트랜잭션도 공유락이 설정된 데이터에 대해서 공유락 설정 가능
- 배타락 (LX, Exclusive Lock)
- 사용중인 데이터에 대해서 다른 트랜잭션이 읽기 X, 쓰기 X
- 다른 트랜잭션은 배타락이 설정된 데이터에 대해서 어떠한 lock도 설정이 불가
- JPA에서의 버전 관리 ( 낙관적인 락 (Optimistic Lock))
- 데이터 갱신 시 충돌이 발생하지 않을 것으로 가정하여 락이 아닌 버전 관리 기능을 통해서 트랜잭션 격리성 관리 및 충돌 방지
- DB가 제공하는 락 기능을 사용하지 않고 JPA가 제공하는 버전 관리 기능을 사용(어플리케이션 단위의 락)
- 커밋 전까지는 충돌을 알 수 없음
- 충돌이 나면 롤백 처리는 개발자의 몫
- 수정의 비율이 높다면 Pessimistic, 읽기의 비중이 높다면 Optimistic 사용
- 2 Phase Locking
- locking 단계를 2개로 구분하여 lock과 unlock하는 시간을 구분하여 동시성 제어
- 직렬 가능성을 보장할 수 있는 규약으로 많이 사용되지만, 교착 상태, 연쇄복귀문제가 발생할 가능성이 있다.
- lock 연산의 대상은 속성 -> 튜플 -> 릴레이션 -> 데이터베이스 순으로 커질수록 lock의 수가 적어지고 제어가 간단하지만 병행성이 떨어지는 단점 (locking 단위가 작을수록 구현은 복잡하지만 lock의 수, 제어기법이 복잡하여도 병행성 높음)
- 확장 단계 (Growing Phase)
- 트랜잭션은 새로운 lock O, unlock X
- 축소 단계 (Shrinking Phase)
- 트랜잭션은 새로운 lock X, unlock O
- 엄격한 2단계 잠금 규약 (Strict 2 Phase Locking)
- 2단계 잠금 규약에서 발생하는 연쇄복귀 문제를 해결
- 모든 X-lock에 대한 unlock 연산은 트랜잭션이 완전히 완료된 후 실행
- 완료되지 않은 트랜잭션에 의해 갱신된 데이터를 다른 트랜잭션이 읽거나 쓰지 못하도록 방지하여 연쇄 복귀 문제 해결
- 대부분의 DBMS에서 엄격한 2PL 규약 사용
- Time Stamp
- DBMS가 부여하는 유일한 식별자인 타임 스탬프(시스템에 들어오는 순서)를 지정하여 트랜잭션 간의 순서를 미리 선택하여 직렬화 하는 방법
- 교착 상태를 방지할 수 있지만 RollBack 발생률이 높고 연쇄 복귀 문제 초래 가능
- TimeStamp 생성 기법
- 논리적 계수기 (Logical Count)
- 트랜잭션 발생시 카운터 증가
- 시스템 클럭 (System Clock)
- 트랜잭션이 시스템이 들어올 때의 시스템 시각 부여
- 논리적 계수기 (Logical Count)
- 낙관적 검증 (Validation)
- 데이터 갱신 시 충돌이 발생하지 않을 것으로 가정하여 락을 걸지 않으며 트랜잭션 수행 동안은 검사하지 않고 트랜잭션 종료시 일괄적으로 검사하는 방법
- 트랜잭션 수행 동안은 트랜잭션을 위해 유지되는 데이터 항목들의 지역 사본에 대해서만 갱신
- 트랜잭션 종료 시에 동시성을 위한 트랜잭션 직렬화 검증이 되면 일시에 DB에 반영
- 다중 버전 동시성 제어 (MVCC)
- 트랜잭션의 타임스탬프와 접근 데이터의 여러 버전 타임 스탬프를 비교하여 직렬 가능성이 보장되는 버전 선택
- 하나의 데이터 아이템에 대해 여러 버전의 값을 유지
- 기록보다는 판독 연산이 주류를 이루는 데이터 베이스 시스템에 유리
- 데이터 아이템을 판독할 때 마다 중복되는 디스크 접근
- 트랜잭션 간의 충돌 문제는 대기가 아니라 복귀처리 -> 연쇄 복귀 문제 발생 가능
- 원리
- 이전의 데이터 값 저장
- 데이터 변경 시 마다 undo 영역에 저장
- SCN 값 기준 Rollback Segment / Undo 영역 기반 동시성 관리
MVCC(격리 수준 제어) 대신 락을 사용하는 이유?
낙관적인 락이나 비관적인 락은 다른 트랜잭션의 쓰기 작업 자체를 막아버리지만 MVCC는 레코드에 잠금을 걸지 않고 트랜잭션 격리 레벨에 따라 Undo 로그에서 데이터를 가져와 일관된 읽기를 제공하기 때문에 두 트랜잭션이 동시 수정 작업시 처음의 수정사항만 반영되도록 하여 갱신 분실 문제를 예방하기 위해서는 락을 사용한다.
낙관적인 락보다 DB 트랜잭션 레벨을 Repeatable Read로 변경한다면?
Repeatable read는 선행 트랜잭션 종료시 까지 다른 트랜잭션이 update, delete 작업하지 못하도록 락을 거는 반면 낙관적인 락은 락을 걸지 않고 트랜잭션 자체를 blocking 하지 않으면서도 다른 트랜잭션이 수정하는 것을 막아준다. 또한 락을 거는 것 자체가 성능에 영향을 줄 수 있기 때문에 격리 레벨을 조정하는 것보다 낙관적인 락을 사용하는 것이 더 좋다.
https://velog.io/@ha0kim/%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%A0%9C%EC%96%B4
https://velog.io/@ha0kim/%EC%9E%A0%EA%B8%88Locking-%EA%B8%B0%EB%B2%95
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=santalsm&logNo=220526219749
https://bubble-dev.tistory.com/entry/DB-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%A0%9C%EC%96%B4
https://mangkyu.tistory.com/30
https://jokerkwu.tistory.com/125
https://www.youtube.com/watch?v=w6sFR3ZM64c&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech
'데이터베이스' 카테고리의 다른 글
ELK스택 기본사용법 - ② Kibana (0) 2022.10.31 ELK스택 기본사용법 - ① ElasticSearch (0) 2022.10.26 조회 성능 개선하기 ( ③ DB 최적화, Replication ) (0) 2022.04.28 조회 성능 개선하기 ( ② 인덱스 설계 ) (0) 2022.04.28 조회 성능 개선하기 ( ① 쿼리 최적화 ) (0) 2022.04.28 -