Transaction(트랜잭션) and 동시성 제어
Mention : 트랜잭션은 나를 너무 편하게 해주고 있었지만, 사실은 생각해야할 것이 많았다🧐
트랜잭션 (Transaction)
- 여러 쿼리를 논리적으로 하나의 작업으로 묶어주는 것
- 거래가 일어날 때의 과정
- 구매자 계좌에서 10,000원 출금
- 판매자 계좌에서 10,000원 입금
- UPDATE 문 : 구매자 계좌에서 10,000원 빼기 → 만약 오류가 발생한다면?
- UPDATE 문 : 구매자 계좌에서 10,000원 더하기
- 하나의 트랜잭션은 커밋 혹은 롤백된다.
- 커밋 - 트랜잭션으로 묶인 모든 쿼리가 성공 → 결과를 DB에 반영
- 롤백 - 오류발생시 →쿼리실행 결과를 취소하고 → DB를 이전으로 되돌림
- 거래가 일어날 때의 과정
- 트랜잭션 범위는 커넥션 기준
- 문제가 발생했을 때 롤백해야 하는 범위
- 트랜잭션 전파
- 여러 메서드 호출이 한 트랜잭션에 묶이도록 하기 위해 필요
- ex) 스프링 프레임워크의 트랜잭션 처리 @Transactional
- 외부 연동이 섞여 있으면 롤백 처리에 주의
- 외부 시스템은 롤백이 안되는 경우
ACID
- 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질
- A (Atomicity, 원자성)
- all or nothing
- 트랜잭션은 DB에 모두 반영되거나, 전혀 반영되지 않아야 한다.
- 완료되지 않은 트랙잭션의 중간 상태를 DB에 반영해서는 안된다.
- C (Consistency, 일관성)
- 트랜잭션 작업처리결과는 항상 일관성 있어야 한다.
- 데이터베이스는 항상 일관된 상태로 유지되어야 한다.
- I (Isolation, 독립성)
- 둘 이상의 트랜잭션이 동시 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다.
- 각각의 트랜잭션은 서로 간섭없이 독립적으로 이루어져야 한다.
- D (Durability, 지속성)
- 트랜잭션이 성공적으로 완료되었으면 결과는 영구히 반영되어야한다.
트랜잭션의 성질
- 성능의 문제 → ex) 동시성 문제
- 경쟁상태 (Race Condition)
- 여러 클라이언트가 같은 데이터에 접근할 때 문제 발생
- 트랜잭션 격리 수준
- 동시에 DB에 접근할 때 그 접근을 어떻게 제어할지에 대한 설정
- 다음은 격리 수준을 나타낸 것이다.
- READ-UNCOMMITTED < READ-COMMITTED < REPEATABLE-READ < SERIALIZABLE
- 격리수준이 높을수록 데이터 정합성이 높으며, 성능(처리량)은 떨어진다.
- 격리수준이 낮을수록 동시성에 대한 성능(처리량)은 좋아진다.
- 데이터 정합성과 성능은 반비례
- 동시에 DB에 접근할 때 그 접근을 어떻게 제어할지에 대한 설정
- READ-UNCOMMITED
- 커밋 전의 트랜잭션의 데이터 변경 내용을 다른 트랜잭션이 읽는 것 허용
- Dirty , Non-Reapeatable, Phantom Read 현상이 나타날 수 있다.
- READ-COMMITED
- 커밋된 데이터만 읽기
- 커밋된 값과 트랜잭션 진행 중인 값을 따로 보관
- 커밋된 데이터만 덮어쓰기
- 행 단위 잠금 사용
- 같은 데이터를 수정한 트랜잭션이 끝날 때까지 대기
- 행 단위 잠금 사용
- 커밋이 완료된 트랜잭션의 변경사항만 다른 트랜잭션에서 조회 가능
- Non-Reapeatable, Phantom Read 현상이 나타날 수 있다.
- 커밋된 데이터만 읽기
- REPEATABLE-READ
- 트랜잭션 동안 같은 데이터를 읽게 함
- ex) MVCC (Multi-Version Concurrency Control)
- 읽는 시점에 특정 버전에 해당하는 데이터만 읽음
- 트랜잭션 범위 내에서 조회한 내용이 항상 동일함을 보장
- Phantom Read 현상이 나타날 수 있다.
- 트랜잭션 동안 같은 데이터를 읽게 함
- SERIALIZABLE
- 한 트랜잭션에서 사용하는 데이터를 다른 트랜잭션에서 접근 불가
- 성능이슈 때문에 인덱스 잠금이나 조건 기반 잠금 등을 사용한다.
Problem
- Dirty read
- 커밋되지 않은 데이터 읽기
- Dirty write
- 커밋되지 않은 데이터 덮어쓰기
- Read skew
- 읽는 시점에 따라 데이터가 바뀜
- Lost Update
- 변경 유실, 같은 데이터를 쓸 때 발생
- ex). count, 위키 페이지 수정
Lost Update 해결방안
- 원자적 연산
- DB가 지원하는 원자적 연산 사용
- 동시 수정 요청에 대해 DB가 순차 처리
- DB가 지원하는 원자적 연산 사용
- 명시적 잠금
- 조회할 때 수정할 행을 미리 잠금
- ex) select…for update
- CAS (Compare at set)
- 수정할 때 값이 같은지 비교
트랜잭션 전파 타입
- 트랜잭션의 경계에서 트랜잭션이 어떻게 동작할 것인가
- 데이터의 안전성에 관한 문제
Summary
- 트랜잭션이란 여러 쿼리를 논리적으로 하나의 작업으로 묶어주는 것 입니다. 트랜잭션으로 쿼리가 묶여있지 않다면, 오류가 발생할 경우 잘못된 결과를 초래할 수 있습니다.
- 하나의 트랜잭션은 커밋 또는 오류가 있을경우 롤백됩니다.
- ACID는 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질입니다.
- 원자는 물질의 최소단위입니다. 따라서 쪼개질수가 없습니다. 따라서 원자성이란, 트랜잭션은 DB에 모두 반영되거나, 전혀 반영되지 않아야 한다는 것입니다.
- 일관성은 트랜잭션 작업처리결과와 데이터베이스는 항상 일관성있어야 한다는 것입니다.
- 독립성이란 둘 이상의 트랜잭션이 동시 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다는 것입니다.
- 지속성은 트랜잭션이 성공적으로 완료되면 결과는 영구히 반영되어야 한다는 것 입니다.
- 잠금 시간은 최소화, 잠금 시간이 길어지면 성능(처리량) 저하
- 동시성 문제를 다룰 때는 사용하는 DB의 기본 격리 레벨 숙지
Reference 📚
Leave a comment