https://codenme.tistory.com/22
위의 자료를 기반으로 작성한 내용입니다. 페이지 별로 관련 내용을 정리한 것이니, 해당 자료와 함께 보는 것을 권장 드립니다.
Transaction의 개념
트랜잭션(Transaction)이란?
데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위를 뜻한다.
각 유저는 혼자 db 사용한다고 생각하도록, 운영되어야하고, 실제로 여러 유저가 동시 접근을 수행하더라도, 에러가 생겨 데이터에 손상이 가서는 안된다.
예시
A 가 어떤 값을 읽으려고 접근하는데, 다른 누군가가 그사이에 해당 값을 바꿨다면, 데이터의 일관성에 문제가 생기는 것이다.
이처럼, DB는 내가 의도한 것을 얻는 것을 “보장” 해주기 위한 'Transaction'이란 연산단위로 나눠서 보증한다.
이와 같은 Transaction 단위 내에서는여러 연산을 동시에 수행해도 안전하게 할 수 있게 보증해주는 것으로, 동시성 문제를 해결한다. 또한, 각 Transaction 내부에서는 문제가 없더라도, 여러 transaction 동시에 발생할 경우 동시성 (concrurrency) 문제, 다양한 failure( HW, System crash)이 존재하기에, 이 역시 고려해야한다.
consistency
- 만약 값이 바뀌게 되면 무조건 변경된 값을 사용자가 확인할 수 있어야한다. ( data)
- 각 트랜잭션은 독립적으로 수행되어야한다.== db consistency 가 보장되어야한다.
- Integrity constraint 가 지켜져야한다. (A가 B에게 송금>>> A와 B 자산 합은 그대로가 되야한다. 등)
Transaction은 일관된 DB를 봐야한다. - Transaction이 성공적으로 끝나면, DB는 consistent해야한다. (은행 송금> A 가 B에게 줌. >> A계좌에서 돈 빠져나가는 것과 B계좌에 돈 들어오는건 같은 Transaction 안에 있어야한다! )
트랜잭션의 ACID 룰
⦁ Atomicity(원자성): 트랜잭션의 모든 연산들이 정상적으로 수행 완료되거나 아니면 전혀 어떠한 연산도 수행되지 않은 상태를 보장해야 한다. atomicity는 쉽게 'all or nothing' 특성으로 설명된다.
⦁ Consistency(일관성): 고립된 트랜잭션의 수행이 데이터베이스의 일관성을 보존해야 한다. 즉, 성공적으로 수행된 트랜잭션은 정당한 데이터들만을 데이터베이스에 반영해야 한다.
의도와 다른 값을 read or write 하거나, 의도치 않게 데이터 손실되는 경우 없어야!
Ex) 시스템의 고정요소는 트랜젝션 수행 전과 후가 같아야 한다. 모든 잔고는 0 이상 이라는 조건이 있다면, 어떠한 트랜잭션이 성공되어도 이 조건이 유지되야함.
⦁ Isolation(독립성): 여러 트랜잭션이 동시에 수행되더라도 각각의 트랜잭션은 다른 트랜잭션의 수행에 영향을 받지 않고 독립적으로 수행되어야 한다. 즉, 한 트랜잭션의 중간 결과가 다른 트랜잭션에게는 숨겨져야 한다는 의미인데, 이러한 isolation 성질이 보장되지 않으면 트랜잭션이 원래 상태로 되돌아갈 수 없게 된다. Isolation 성질을 보장할 수 있는 가장 쉬운 방법은 모든 트랜잭션을 순차적으로 수행하는 것이다. 하지만 병렬적 수행의 장점을 얻기 위해서 DBMS는 병렬적으로 수행하면서도 일렬(serial) 수행과 같은 결과를 보장할 수 있는 방식을 제공하고 있다.
⦁ Durability(지속성): 트랜잭션이 성공적으로 완료되어 커밋되고 나면, 해당 트랜잭션에 의한 모든 변경은 향후에 어떤 소프트웨어나 하드웨어 장애가 발생되더라도 보존되어야 한다.
ACID 가 지켜질수록 안전하지만, Concurrency가 나빠져 성능이 떨어진다
Ex) isolation level이 높아질수록 더 많이, 더 빡빡하게 lock을 건다 -> 동시성 떨어진다.
Isolation requirement
DB에 서로 다른 유저가 동시에 접근 하여도 각 유저는 성능적으로 혼자 사용하는 것처럼 느껴져야한다.
( Ti, Tj 가 있을 때, Ti 가 끝나고, Tj 가 시작하는 “것처럼” 보이게 수행되어야한다.)
예시
A라는 유저가 task1, tast2 진행하려한다. 중간에 B 가 X라는 작업하면
task1>X> task2 이런식으로 처리되지만, 각 유저는 각자 자신의 작업만 수행된 듯 보여져야한다.
Isolation 이 지켜지지 않는다면, 트랜잭션이 원래 상태로 되돌아갈 수 없게 된다. Isolation 성질을 보장할 수 있는 가장 쉬운 방법은 모든 트랜잭션을 순차적으로 수행하는 것(sequential)이다. 하지만 병렬적 수행의 장점(t높은 성능)을 얻기 위해서 DBMS는 병렬적으로 수행하면서도 일렬(serial) 수행과 같은 결과를 보장할 수 있는 방식을 제공하고 있다. 이는 뒤에서 설명하겠다.
Transaction State( 트랜잭션 상태 )
트랜잭션은, 5가지 상태로 구분되어 관리된다.
Active:초기 state
Partially commit: 마지막 statement 종료 직후
Fail: transaction 수행하다 오류 등으로 끝까지 못함
Aborted: fail 등 상황에서 transaction rollback한다.
Commit: Transaction이 종료되어 반영되는 것
이제 각 State에 대해 자세히 살펴보자.
Transaction 종료: 실패, 성공에 따라 aborted or committed로 나뉜다.
하지만, 위의 2가지 상태만으론 몇가지 문제점이 생긴다.
commited의 durability 문제
final statement가 끝나도 여전히 실제 정보가 disk가 아닌 main memory에만 존재할 수 있다. 이 경우, HW fail 등 문제상황이 생기면, 'Commited' 처리된 데이터가 유실된다.
이러한 상황을 구분하고자 partial committed state 가 생겼다.
partialy Commited 상태에서 recovery를 위한 충분한 정보를 disk에 write해야만 committed state가 된다. (문제 생겨도 복구 가능한 상태로 만들기)
aborted의 atomicity 문제
Transaction 주간에 abort 수행 시, 앞선 절반이 update되는 상황이 발생할 수 있다.
Abort된 transaction은 DB에 영향을 주면 안된다. 따라서, 그동안 반영했던 update들은 undo 해야한다.
모두 undo하면 그 transaction이 rollback 되었다고 한다.
Concurrent Executions
앞서서, 여러 Transaction이 Serial하게 가지 않고, 병렬적으로 처리 될 시에, 성능적으로 많은 이점이 존재한다고 했는데, 이것에 대해 조금 더 자세히 설명하겠다.
여러 transaction이 동시에 system에서 동작할 시 장점
- processor 증가, disk 활용도가 올라간다 >> transaction throughput 증가
ex)여러 transaction이 각각 한 개는 CPU에서, 또 하나는 Disk에서 Write ….) - transaction에 대한 response time 이 줄어든다: short transaction이 Long transaction을 기다릴 필요가 없다.
Concurrency control schemes
Concurrent한 transaction 허용할 시, DB의 consistency를 파괴할 수 있기에, 이를 방지하고 Isolation을 얻기 위해 스케쥴을 짜는 것을 의미한다.
Serializable
Transaction 1개씩 순차적으로 실행되게 하는 방법은 느리지만, 안전한 스케줄을 제공한다. 따라서, 병렬적 처리를 진행했을 때 성공적인 스케줄인가? 에 대한 판단 여부는, Serial 스케줄과 '동일한 결과'를 반환하는가? 를 기준으로 평가할 수 있다. 이와 같이, concurrent한 transaction 환경에서 serial 환경과 모든 상황에서 같은 환경을 유지하는 스케줄(Sched)를 Serializable 스케줄 이라고 한다.
예시
T1: A계좌가 50만큼 B계좌에 이체
T2: A계좌에 10% 빼서 B계좌로 이체.
Sched 1) T1 먼저 전부, 그리고 T2 전부.
Sched 2) T2먼저 전부, 그리고 T1 전부.
스케줄 1,2는 serial하게 진행되었기에, 안전하다.
Sched 3: A+B의 결과가 Serial한 Sched 1,2와 같다. 따라서, 해당 스케줄을 Serializable하다.
Sched 4: A-50을 한 뒤에, Write 없이 다시 read(A) >> Update된 A값이 읽어지지 않고, 기존의 A 값이 읽어 들여진다. 따라서 Serializable하지 않은, 위험한 스케줄링이다.
Serializability
각 transactoin은 database Consistency가 보장된 환경이라 가정해보자. 이런 환경에서는, serial 스케줄이 Database consistency 보장한다. 그렇기에 이 상황에서 어떠한 스케줄이 Serializable한지( Serial 스케줄과 같은 결과인지)를 통해
데이터 스케줄의 안정성을 평가할 수 있다.
이를 스케줄러 입장에서 본다면, read, write 연산의 순서를 위주로 판단하면 쉽다.
why?
read, write 순서 바꿀 때 실제 결과가 달라질 수 있다. 만약 서로 다른 두개의 트랜잭션이 동일한 데이터 소스 접근 시의 연산이 (R,R),(W,R), (R,W),(W,W) 라면?
만약 두 연산의 순서를 바꾸려고 한다면, (R,R) 제외 전부 conflict가 발생한다. 이는 exclusive lock이 write lock, shared lock이 read lock인 이유이기도 하다.
따라서, Serializable 스케줄을 찾기 위해, Write, Read의 순서를 바꿔보며, Conflict가 발생하지 않는 순서를 찾으면 된다.
Conflict Serializability
위의 내용을 고려해서 Conflict가 발생하지 않도록 Read, Write연산의 순서를 바꿔서 같아 질 수 있는 스케줄링은, Conflict 관점에서 유사한 안정성을 가진다. 이를 기반으로 Conflict-Equivalent라는 지표를 세워 스케줄을 비교할 수 있다.
conflict equivalent
S1과 S2가 conflict equivalent 하다 == S1 스케줄이 non-conflict 한 연산들을 swap해서 S2로 바뀔 수 있다.
conflict serializable
S가 conflict serializable 하다: S가 임의의 serial 스케줄과 conflict equivalent 하다.
Conflict가 발생하는 경우, 순서를 원래대로 두고, Conflict가 발생하지 않느다면 순서를 변경한다. 같은 transaction안에서 연산순서는 유지하되, 중간 중간 들어오는 다른 transaction들과의 순서는 바꿔도 된다. 이와 같이, Conflict 발생 여부를 통해 Transaction을 비교하는 것 만으로도, 트랜잭션의 안정성을 검증할 수 있다.
주의: 내부 순서는 바뀌면 안된다.
T1 이 1>2>3 이고 T2가 a>b>c 일시
1>a>2>3>b>c를 1>2>3>a>b>c 이런 식으로 해볼 순 있어도
1>3>2 >a>b>c 이런 식으로 transaction 내부 순서는 바꾸면 안됨( transaction 의미 상실)
예시 1
Serial 스케줄인 Sched 6와 conflict equivalent 한 Sched 3. 따라서 Sched 3는 conflict serializable.
각 data item 기준으로 순서가 동일하다 )
A: T1 rw , T2 rw
B: T1 RW ,T2 RW
예시 2
(R,R) 제외하면 순서 바꿀 때 Conflict가 생긴다.
만약 T1, T4가 Serial 하게 진행 된다면, <T3,T4> or <T4,T3> 순서로 가야하는데, 두 스케줄 모두 Conflict-Equivalent하지 않기에, 위 스케줄은 Conflict-Serializable 하지 않다.
<T3,T4> : 이 스케줄을 final write가 T4의 write. 따라서 마지막에 남은 Q 가 달라져서 x
<T4,T3> : T4의 write 후, T3의 read 발생하지만, 위의 스케줄은 반대. 따라서 x
요약
Conflict serializability: conflict 가 발생하지 않는 Read,Read 연산끼리 끼리 순서를 바꿔서 Serial한 스케줄과 같은 결과를 낼 수 있는가? 를 측정하는 방식이다.
precedence graph
Conflict serializable 을 테스트하기 위한 그래프 이다.
N개 transaction이 동시 수행 시, 상대적으로 먼저 수행해야하는 순서가 있을 수 있다.
N개의 transaction에 같은 data item이 쓰인다면, R>W,W>R, W>W 에 대해 그래프를 그린다.
만약 사이클 발생 시, conflict serializable 하지 않은 것이다.
반대로 사이클이 없다면, topological sort( 그래프 edge 방향성 유지한채 1줄로 정렬) 로 conflict equivalent 만족하는 serializable 스케줄 구할 수 있다
예시
이제, Precedence 그래프를 그려서 어떠한 스케줄이 Conflict Serializable인지 검증하고, 맞다면 Srial한 스케줄을 찾는 과정을 살펴보자.
아래로 내려가며 RR제외하고 찾아지는 걸 directed edge로 표현하여 그래프를 완성한다.
이후 해당 그래프에 대한 topological sort 로 구해지는 경우의 수들이 가능한 모든 serializable order 이다.
Recoverable Schedules
Transaction이 중간에 실패한 경우, 우리는 해당 트랜잭션을 복구(recover)해야한다.
Recoverability란?
트랜잭션이 실패했을 때 회복가능성을 의미한다. 트랜잭션은 atomicity가 보장되어야하므로, 트랜잭션이 실패하면, 트랜잭션 이전 상태로 복원될 수 있는 Recoverability를 가지고 있어야한다.
Recoverable schedule
Recoverable한 경우
T9이 T8에 의해 write된 데이터를 read할 때, T8의 commit이 T9의 commit 이전에 발생하면 recoverable하다.
이는 T9이 읽은, T8이 write한 데이터가 commit 되어 안정성이 보장되었기 때문에, T9을 다시 수행해도 이전과 다른 데이터를 읽을 문제가 없기 때문이다. 이처럼, DBMS는 반드시 schedule이 recoverable하도록 보장해야 한다.
Recoverable하지 않은 경우
Ti가 commit하기 전에 Tj가 commit하였는데, Ti가 abort되면 recoverable하지 않다.
Cascadeless Schedules
cascading rollback
recoverable한 스케줄의 경우, read한 값을 write한 트랜잭션의 종료를 대기해야하는데, 만약 해당 트랜잭션이 abort되면 자신도 abort 되는데, 이러한 관계가 연계적으로 일어나 일련의 트랜잭션 rollback을 양산할 수 있는데 이를 cascading rollback 이라고 한다.
예시
위 스케줄은 아무것도 commit 되지 않았기에 recoverable 하다.
만약 T10이 fail했고, abort 되었다면, T10에서 write한 정보를 read하는 T11, T12 도 rollback되야한다.
이러한 Cascading rollback은 엄청난 낭비를 발생시킨다.
그렇기에, 이러한 Cascading rollback 현상을 방지하는 스케줄인 Cascadeless Scedule이 존재한다.
cascadeless schedule이란?
cascade rollback이 발생하지 않는 스케줄이다.
T1가 write한 데이터를 T2 가 읽는다면 , T2 의 read 전에 T1를 commit 하는 것으로 cascade rollback을 방지한다.
그리고 모든 cascadeless 스케줄은 recoverable하다.
Cascadeless schedule의 단점
CaseCadeless 스케줄은 확실히 cascade rollback으로 인한 비정상적인 성능 저하를 방지해주지만, 이로인해, concurrency는 많이 떨어질 수 있다. 왜냐하면 특정 트랜잭션이 commit할 때까지 다른 트랜잭션이 기다려야 하는 경우가 생기기 때문에 트랜잭션 결과를 바로바로 처리할 수 없는 경우가 생기기 때문이다.
요약
트랜잭션 A,B A의 write 값을 B 가 읽는다 가정
- Recoverable: A가 commit 되기전까지 B도 commit 수행 x
- Cascadeless: A가 commit 되기전에 B가 문제되는 Read 수행 x
Casecadeless 가 recoverable 보다 더 엄격한 case이다.
Concurrency Control (동시성 제어)
Concurrency: 여러 개 transaction 동시에 수행하더라도, 안정성을 보장해야한다.
Db시스템에서 모든 스케줄은
⦁ Db의 consistency를 위해 Conflict or view serializable 하고, 복구 가능하도록 recoverable 해야 한다.
⦁ 또한 Performance 위해 완벽히 cascadeless 여야 한다.
1번에 transaction 1개씩 순차적으로 진행한다면 ( serial schedule) 안전하지만, 성능 상 concurrency하게 트랜잭션을 수행하는 것은 필연적이다.
따라서, Concurrent 스케줄을 위한 concurrency control protocol이 필요하다.
역시 casecadeless, recoverable, Conflict or View Serializable 해야한다.
Conflict 적용 porotocol, View 적용 protocol과 같이 다른 protocol은 다른 overhead 생긴다.
따라서 Precedence 그래프를 사용하는 대신, 규칙을 지정해 non-serializable 스케줄을 피한다.
(위의 내용은, Concurrency에 대한 글에서 자세히 다루겠다.)
트랜잭션의 안정성과 성능간의 Trade-off
- 항상 serializable하지 않더라도, 빠른 성능 원하면 조절해서 사용할 수 있다.( 안전을 일부 포기하고 속도를 챙기는..)
- 몇몇 애플리케이션들은 의도적으로 낮은 수준의 consistency를 보장하기도 한다. 이는 serializable가 가능하지 않은 스케줄을 허락함으로써 구현 속도 상승을 도모하는 것이다. ( 안전과 tradeoff)
- 예를 들어, 모든 계좌의 대략적인 전체 잔고를 계산하는 read 가능한 트랜잭션, 쿼리 최적화를 위해 계산된 데이터베이스 통계는 대략적인 추정을 얻는 기능 이다. 따라서 이러한 트랜잭션은 다른 트랜잭션과 관련하여 serialize 하여 정확성을 챙길 필요가 없고, read 연산만 존재하기에 안정성을 해치지도 않는다. 이런 기능의 경우 의도적으로 consistency 레벨을 낮추어 성능의 향상을 도모할 수 있다.
Levels of Consistency
SQL에서는 다음과 같은 isolation level들을 제공한다.
Serialiazable > Repeatable read > Read committed > Read uncommitted
왼쪽으로 갈 수록 안전성을 보장하고 느린 Level이고, 오른쪽으로 갈 수록 안정성이 보장되지 않지만 빠른 Level이다.
적절한 level을 선택하여 Isolation 과 Concurrency 사이의 tradeoff를 적절하게 관리할 수 있다.
Serializable
Data Consistency가 보장되면 완벽하게 안전한 가장 안전한 레벨이다. 계속 언급했었으니 넘어가겠다.
Repeatable read
read는 오직 commit된 데이터만 읽을 수 있도록 하고, 트랜잭션에 의한 read 사이에서 다른 트랜잭션이 update를 할 수 없도록(반복읽기) 한다.
문제: 어떤 트랜잭션이 특정 조건을 만족하는 데이터를 찾을 때, 트랜잭션은 commit된 트랜잭션에 의해 삽입된 데이터의 일부는 찾을 수 있지만, 동일한 트랜잭션에 의해 삽입된 다른 데이터를 찾을 수 없다.
Read committed
오직 commit된 데이터만 읽을 수 있도록 하지만 반복 읽기는 요구하지 않는다.
예를 들어, 트랜잭션의 두번의 읽기 사이에서, 다른 트랜잭션은 데이터를 update를 하고 commit할 수 있다. (즉, A 트랜잭션이 read(Q)를 두번 할 때, read(Q) 사이에 B가 write(Q)를 하고 commit할 수 있다.)
Read uncommitted
commit 하지 않은 데이터도 read 할 수 있다.
DB는 여러 사용자가 동시에 요청하는 상황이 빈번하다. 각 요청을 순서대로 처리하면 성능이 매우 나빠진다.
따라서 transaction 별로 조금씩 가져오되, transaction 내부 순서는 유지하고, 적절한 Consistency 정책을 구성하는 것으로, 동시 접근 상황에서도 안정성을 유지할 수 있다.
'데이터베이스(rebooting now)' 카테고리의 다른 글
[db] recovery system (1) | 2022.12.27 |
---|---|
[db] concurrency (0) | 2022.12.27 |
[db] query optimization (1) | 2022.12.27 |
[db] query processing (1) | 2022.12.26 |
[db] indexing part-2 (B+ Tree) (0) | 2022.12.26 |