새로운 내용을 공부할 때
새로운 내용의 공부를 시작할 때 용어의 정의를 이해하지 못하거나 정확하게 알지 못한다면 그 용어가 포함된 문장을 이해하지 못합니다.
작은 단어 하나가 내용을 이해하지 못하게 하기 때문에 용어를 정확하게 이해하는 것이 중요합니다.
concurrency control 기초 학습
목표 D-day : 35 일
학습목표
DB에서 Concurrency control이 트랜잭션의 isolation을 보장하기 위해 serializability 개념을 사용합니다.
serializability가 어떤 개념인지 학습합니다.
Schedule 성능
Serial - 직렬로 처리함
- 트랜 잭션 A 는 타인 계좌에 20만원 입금
- 트랜잭션 B 는 내 계좌에 30만원 입금
serial Schedule은 하나의 트랜잭션이 완료될 때 까지 다른 트랜잭션을 실행하지 않습니다.
트랜잭션 A : 내 계좌 조회 → 내 계좌 20만원 빼기 → 타인 계좌 조회 → 타인 계좌 20만원 넣기
위 트랜잭션 A가 모두 종료가 될때 까지 트랜잭션B는 기다립니다.
CPU는 계좌 조회나 출금 작업 등에서 디스크 I/O가 발생할 때, 시스템 콜을 통해 디스크 작업을 요청하고, 그 응답이 돌아올 때까지 대기하게 됩니다.
그러는 동안 CPU는 아무 작업을 하지 않고 놀게 됩니다.
트랜잭션 A가 모두 종료가 되어야 다른 트랜잭션을 실행하기 때문에 오퍼레이션이 중간에 섞이면서 예상하지 않은 결과를 만들어내지 않습니다.
한 번에 하나의 Transaction 만 실행되기 때문에 좋은 성능을 낼 수 없고, 현실적으로 사용할 수 없는 방식입니다.
NonSerial - 직렬로 처리하지 않음
- 트랜 잭션 A 는 타인 계좌에 20만원 입금
- 트랜잭션 B 는 내 계좌에 30만원 입금
트랜잭션 A : 둘리 계좌 조회 → 둘리 계좌 20만원 빼기 → 희동이 계좌 조회 → 희동이 계좌 20만원 넣기
트랜잭션 B : 희동이 조회 → 희동이 30만원 넣기
Serial방식은 트랜잭션 A → 트랜잭션 B 혹은 트랜잭션 B → 트랜잭션 A 와 같이 동작합니다.
트랜잭션 하나가 마무리가 되어야 다른 트랜잭션이 공유자원에 접근할 수 있습니다.
하지만, NonSerial은 트랜잭션내 작업 순서는 동일하지만 트랜잭션 A와 B가 동시에 일어납니다.
희동이 계좌조회(B) → 둘리 계좌 조회(A) → 희동이 30만원 넣기(B) → 둘리 계좌 20만원빼기(A) → 희동이 계좌조회(A) → 희동이 계좌 20만원넣기(A) 와 같이 CPU가 디스크 I/O 작업을 맡기고 돌아오는 동안 다른 작업을 할 수 있습니다.
Step | Transaction | Operation |
---|---|---|
1 | B | 희동이 계좌 조회 |
2 | A | 둘리 계좌 조회 |
3 | B | 희동이 계좌 30만원 넣기 |
4 | A | 둘리 계좌 20만원 빼기 |
5 | A | 희동이 계좌 조회 |
6 | A | 희동이 계좌 20만원 넣기 |
NonSerial 방식은 트랜잭션 B의 Operation으로 디스크 I/O로 넘기면서 CPU는 대기하는 것이 아닙니다.
CPU는 그동안 트랜잭션 A를 진행합니다. 트랜잭션 A의 Operaion으로 디스크 I/O가 발생하면 트랜잭션 B의 다음 Operation을 실행하기 때문에 동시성이 높아져서 같은 시간동안 더 많은 Transaction 들을 처리할 수 있습니다.
동시성이 높다의 의미는 동시 실행이 가능한 정도가 높다는 의미입니다.
NonSerial 단점
트랜잭션 A와 트랜잭션 B 이 어떤 형태로 겹쳐서 실행되는지에 따라 이상한 결과가 나타납니다.
Step | Transaction | Operation |
---|---|---|
2 | A | 둘리 계좌 조회 |
5 | A | 둘리 계좌 20만원 빼기 |
1 | B | 희동이 계좌 조회 |
4 | A | 희동이 계좌 조회 |
3 | B | 희동이 계좌 30만원 넣기 |
6 | A | 희동이 계좌 20만원 넣기 |
위와 같이 트랜잭션 A와 B가 희동이 계좌를 조회하면 트랜잭션 A가 수행할 20만원 입금 작업이 트랜잭션 B의 입금 결과와 충돌해 희동이 계좌의 최종 잔액이 예상과 다른 값으로 남게 될 수 있습니다.
아이디어
NonSerial 방식으로 성능을 높이고, 이상한 결과를 만들지 않기 위해서는 Serial 방식과 동일한(equivalent) NonSerail schedule을 실행하면 됩니다.
그러면 schedule이 동일하다의 의미를 파악하고 정의하면 됩니다.
Conflict
두개 이상의 Operations이 있을 경우에 사용하는 개념입니다.
세 가지 조건을 만족하면 conflict라고합니다.
- 서로 다른 transaction의 소속되어야합니다.
- 같은 데이터에 접근해야합니다.
- 최소 하나는 write operation이여야합니다.
두 개의 Operation
이 위 3가지 조건을 만족하면 Operation Conflict 하다고 합니다.
둘리 조회 → 둘리 입금 → 희동이 조회(B) → 희동이 입금(B) → 희동이 조회(A)
→ 희동이 입금(A)
- 서로 다른 트랜잭션의 소속되어있습니다.
- 같은 데이터(희동이 계좌)에 접근합니다.
-
최소 하나는 write operation을 합니다.(
희동이 입금A
) -
read-write conflict
희동이 조회(B) → .. →
희동이 입금(A)
희동이 입금(B) →
희동이 조회(A)
같은 자원에 다른 트랜잭션이 접근해서 읽고, 쓰는 작업을 말합니다.
-
write-write conflict
.. → 희동이 입금(B) → …→
희동이 입금(A)
같은 자원에 다른 트랜잭션이 접근해서 쓰고,쓰는 작업을 말합니다.
Conflict가 중요한 이유
conflict operation은 순서가 바뀌면 결과도 바뀌기 때문입니다.
둘리 조회 → 둘리 입금 → 희동이 조회(B) → 희동이 입금(B) → 희동이 조회(A)
→ 희동이 입금(A)
현재 희동이 입금(B) → 희동이 조회(A)
이 부분의 순서가 바뀌게 된다면 전체적인 순서도 바뀌게 되고
희동이 조회(A)
의 결과도 변경됩니다. 이 말뜻이 무슨말이냐면
트랜잭션 B가 입금이 되고 희동이 조회(A)를 하면 입금된 금액(+30)의 결과를 확인할 수 있지만
희동이 조회(A)가 먼저 일어나고 트랜잭션(B)가 발생하면 입금되기전 금액의 결과가 발생합니다.
Conflict equivalent
두개의 스케줄에서 두 조건 모두 만족하면 conflict equivalent 하다고 합니다.
- 두 스케줄은 같은 트랜잭션을 가진다.
- 어떤(any) conflict operation의 순서도 양쪽 스케줄과 동일하다.
스케줄 1과 스케줄 2를 비교하면 됩니다.
스케줄1
둘리 조회 → 둘리 입금 → 희동이 조회(B) → 희동이 입금(B) → 희동이 조회(A)
→ 희동이 입금(A)
스케줄2
희동이 조회(B) → 희동이 입금(B) → 둘리 조회 → 둘리 입금 → 희동이 조회(A)
→ 희동이 입금(A)
- 두 스케줄 1,2는 모두 동일한 트랜잭션 A,B를 가지고 있습니다.
- 스케줄 1은 Serial 스케줄과 Conflict Operation 순서가 동일하므로, Conflict Serializable하다고 할 수 있습니다. 이는 트랜잭션을 직렬화된 스케줄과 동일하게 실행하면서 성능 최적화와 안정성을 모두 확보할 수 있음을 의미합니다.
- 스케줄 1 - 희동이 조회(B) -> 희동이 입금(A)
- 스케줄 2 - 희동이 조회(B) -> 희동이 입금(A)
그외 다른 모든 Conlict Operation을 비교하여 순서가 동일한지 비교합니다
3개의 Conflict Operation이 모두 동일하므로
스케줄 1,2는 Conflict equivalent 하다고 할 수 있습니다.
이유는 Conflict 순서가 동일하다면 동일한 결과를 만들기 때문입니다.
스케줄 2는 Serial 스케줄이므로 안전한 결과를 만듭니다. 스케줄 1은 Serial 스케줄과 Conflict Oprations가 동일하므로 동일한 결과를 동시성을 높이게 실행할 수 있으면서 결과도 동일하다고 정의할 수 있습니다.
이렇게 Serial 스케줄과 conflict equivalent 할 때 Conflict serializable하다고 합니다.
정리하면
스케줄 1은 conflict serializable하다고 할 수 있습니다.
NonSerial 스케줄이지만 Serial 스케줄과 동일한 결과를 만들 수 있다는 걸 알 수 있습니다.
트랜잭션 2개로 만든 Serial 스케줄은 2개밖에 없습니다.
NonSerial 스케줄이 2개의 Serial 스케줄과 Conflict Operation을 비교하여 다른 경우 해당 NonSerial 스케줄은 Non Conflict Serializable 하다고 합니다.
결과가 다르다는 의미입니다.
해결책
NonSerial 스케줄중에서 Serial 스케줄과 Conflict equivalent 하다면 Conflict serializable 하기에 동일한 결과를 만들 수 있고,
성능 문제도 해결할 수 있습니다.
- 여러 트랜잭션이 실행 될때마다 해당 스케줄이 conflict equivalent 한지 확인하는 방법
- 여러 트랜잭션이 동시에 실행해도 스케줄이 conflict seriabilzable하도록 보장하는 프로토콜을 사
정리
- “1. 어떤 스케줄이 하나의 Serial 스케줄과 equivalent 하다면 serializable하다고 할 수 있습니다.”
- “2. 어떤 스케줄이 하나의 Serial 스케줄과 conflict equivalent 하다면 conflict serializable하다고 할 수 있습니다.”
- “3. 어떤 스케줄이 하나의 Serial 스케줄과 view equivalent 하다면 view serializable하다고 할 수 있습니다.”
그 어떤 스케줄도 serializable
하게 만들어주는 것이 concurrency control입니다.
concurrency control이것과 밀접하게 관련있는 트랜잭션 속성이 Isolation입니다.
Isolation을 높여서 serializablity하게 만들면 그만큼 성능은 내려가게 됩니다.
개발자들이 성능과 안전한 결과를 만드는 것을 선택할 수 있도록 제공하는 것이 Isolation level입니다.
생각 재정리
트랜잭션 A와 트랜잭션 B가 오류 없이 동작하기 위해서는 직렬 스케줄로 동작해야 합니다. 하지만 직렬 스케줄은 CPU 자원을 효율적으로 활용하기 어렵고, 디스크 I/O 대기 시간 동안 CPU가 빈 상태로 남아 비효율이 발생합니다.
비직렬 방식에서는 트랜잭션 A의 작업이 시스템 콜을 통해 대기하는 동안 CPU가 트랜잭션 B의 작업을 처리하여 동시성을 높이고, 결과적으로 성능을 개선합니다. 그러나 비직렬 방식은 연산 순서가 엇갈리면서 예상과 다른 결과를 초래할 수 있는 위험이 있습니다.
따라서 성능을 최대한 유지하면서도 예상한 결과를 일관되게 유지하기 위해, 직렬 스케줄과 동일한 순서로 연산을 진행해야 합니다. 두 트랜잭션이 동일한 공유 자원에 접근하고 변경하는 과정이 직렬 스케줄과 같다면, 이는 직렬화 가능한 비직렬 스케줄로 동작할 수 있습니다.
이렇게 직렬화된 스케줄과 동일한 결과를 보장하면서 동시성의 성능을 유지하도록 도와주는 것이 바로 Isolation Level입니다. 개발자는 이 Isolation Level을 조정해 성능과 데이터 일관성 간의 균형을 선택할 수 있습니다.
댓글남기기