1. Transaction
[1] Transaction이란
트랜잭션은 DB에서 논리적 작업을 처리하기 위한 쿼리 집합으로, 트랜잭션에 묶인 모든 쿼리를 수행하거나 모두 실행하지 않습니다. 즉 쿼리 집합을 atomic하게 처리합니다. 이를 위해 로그를 참조하여 commit or rollback연산을 수행합니다.
[2] Commit 연산
- 커밋 연산은 트랜잭션 처리가 정상적으로 종료되어 트랜잭션이 수행한 변경 내용을 DB에 반영하는 연산입니다.
- 트랜잭션이 완료되면 DB는 새로운 정보로 변경되며, 이 정보는 시스템에 오류가 생겨도 취소되지 않게 개발합니다.
[3] Rollback 연산
- 롤백 연산은 트랜잭션 처리가 비정상적으로 종료되어 트랜잭션에 모든 변경 작업을 취소하고 이전 상태로 되돌리는 연산입니다.
- 롤백 연산 시 해당 트랜잭션은 받았던 자원을 모두 반환하고 이전 데이터로 원복합니다.
[4] Transaction Example
성호가 은경에게 5000원을 계좌 이체하는 트랜잭션입니다. 1번, 2번 업데이트 SQL은 실행 순서는 상관없지만 두개가 atomic하게 처리해야합니다. 만약 하나만 실행된다면 5000원이 없어지거나 혹은 더 생기는 문제가 발생합니다.
즉, 1번과 2번 연산이 모두 정상적으로 수행되면 커밋 연산으로 반드시 DB에 반영하고, 하나라도 비정상적 처리가 일어난다면 롤백 연산으로 이전 상태로 원복합니다.
[5]트랜잭션을 사용할 때 주의점
트랜잭션은 꼭 필요한 최소의 코드에만 적용하는 것이 좋으며 또한 트랜잭션의 범위를 최소화해야합니다.
- 트랜잭션 범위를 최소화해야합니다. Isolation Level에 따라 특정 트랜잭션이 자원에 접근하는 동안 다른 트랜잭션은 해당 자원에 접근하지 못하여 대기하는 경우가 발생합니다.
- 꼭 필요한 코드에만 적용하는것이 좋습니다. 일반적으로 DB 커넥션 갯수는 제한적입니다. 중구난방으로 트랜잭션을 적용하면 여유 커넥션을 다 사용하고 있을 때 대기하는 문제가 발생합니다.
2. Transaction 특성, ACID
[1] Atomic (원자성)
- 트랜잭션 연산은 DB에 모두 반영되던지 아니면 전혀 반영되지 않아야합니다. 만약 하나의 쿼리만 실행된다면 데이터의 일관성이 깨지는 문제가 발생합니다.
- 예를 들어 A 계좌에서 B 계좌로 5,000원을 이체하는 트랜잭션이 완벽히 수행되면 커밋 연산을 수행해서 DB에 반영하고 트랜잭션 중간에 오류가 발생한다면 롤백 연산을 수행하여 그때까지 수행된 트랜잭션 연산을 모두 취소하여 원래 상태로 원복합니다.
[2] Consistency (일관성)
- 트랜잭션이 성공 혹은 실패하더라도 시스템이 가지고 있는 고정 요소는 트랜재션 수행 전과 수행 후의 상태와 동일 해야합니다. 즉, 일관성있는 데이터를 제공해야합니다.
- 예를 들어 A 계좌에서 B계좌로 이체할 때 계좌 이체 전후 금액의 합계는 동일해야합니다.
[3] Isolation (독립성)
- 한 트랜잭션이 데이터를 갱신하는 동안 갱신중인 데이터에 다른 트랜잭션들이 접근하지 못하도록 해야합니다. 만약 접근을 허용할 경우 데이터의 일관성이 깨지는 문제가 발생합니다.
- 예를 들어, A 계좌에서 B 계좌로 5,000원을 이체하는 트랜잭션을 수행하는 동안에는 다른 트랜잭션이 A 계좌와 B 계좌에 접근할 수 없습니다.
[4] Durability (연속성)
- 성공적으로 수행된 트랜잭션은 SW, HW 장애가 발생하더라도 변경 결과가 영구적으로 반영되어야 합니다.
3. 병행 제어
동시에 여러 개의 트랜잭션을 병행 수행할 때 데이터의 일관성은 유지하고 단위 시간당 트랜잭션 처리 건수를 최대화 하기위해 노력합니다.
[1] 발생 가능 문제점
- Lost Update : 두 개 이상의 트랜잭션이 같은 데이터를 공유하여 갱신시 데이터가 덮어써져 갱신 결과의 일부가 없어지는 현상을 말합니다.
- Inconsistency : 데이터 갱신이 끝나지 않은 시점에서 다른 트랜잭션이 해당 데이터를 조회하여 모순된 데이터를 읽는 현상을 말합니다.
- Cascading Rollback : 병행 수행되던 트랜잭션들 중 어느 환경에 문제가 생겨 롤백하는 경우 다른 트랜잭션들도 롤백되는 현상을 말합니다.
[2] 병행 제어 기법 > Locking
- 하나의 트랜잭션이 데이터를 엑세스 하는 동안 다른 트랜잭션은 그 데이터를 엑세스 할 수 없습니다. 트랜잭션은 데이터를 엑세스 하기 전에 Lock을 요청하고 엑세스를 마치면 Lock을 해제합니다.
- CRUD의 접근에 Isolation Level을 설정하여 병행성과 일관성을 적절히 유지합니다.
- 하지만 Deadlock의 문제점이 존재한다.
4. DeadLock
여러개의 트랜잭션을 사용하면 교착상태가 일어날 수 있습니다. 교착상태란 두 개 이상의 트랜잭션이 특정 자원 (테이블 혹은 행)의 잠금을 획득한 채 다른 트랜잭션이 소유하고 있는 잠금을 요구하며 무한 대기하는 상태를 말합니다.
교착 상태의 빈도를 낮추는 방법
- 트랜잭션을 자주 커밋합니다.
- 정해진 순서로 테이블에 접근합니다.
- Isolation Level을 높여 직렬화 상태로 만듭니다. 동시성은 떨어지지만 교착상태를 좀 더 피할 수 있습니다.
5. Transaction Isolation Level
여러 트랜잭션이 동시의 어떤 데이터에 접근할 때 어디까지 제어할지를 설정합니다. 격리 수준을 엄격히 제어하면 데이터의 안정성은 높아지지만 동시성 성능이 떨어집니다. 따라서 상황에 맞게 고립 레벨을 설정하는것이 좋습니다. 대부분의 DB는 Read Committed가 기본 수준입니다.
[1] READ UNCOMMITTED
- 어떤 트랜잭션이 데이터 변경 내용을 커밋 하기전에, 다른 트랜잭션이 변경한 데이터를 읽을 수도 있습니다.
- Dirty Read : 만약 T-A가 커밋 하지 않고 롤백 한다면, T-B는 잘못된 데이터를 처리하는 문제가 발생합니다.
[2] READ COMMITTED
- 트랜잭션 커밋이 완료된 변경사항만 다른 트랜잭션에서 조회가 가능합니다.
- Non-Repeatable Read : 같은 트랜잭션 내에서 select문을 조회했는데, 데이터가 다르게 나올 수도 있습니다.
[3] REPEATABLE READ
- 트랜잭션 범위 내에서 조회한 내용이 항상 동일함을 보장합니다. 즉, 한번 조회한 내용은 같은 트랜잭션 내에서 같은 값을 반환합니다.
**Phantom Read (Non Repeatable Read 현상의 한 종류)**
T1이 A 테이블에서 데이터를 Select 한 후, T2에서 A 테이블에 데이터를 삽입 or 삭제 하는 상황에서 T1이 다시 A 테이블에서 데이터를 Select 할 경우 데이터가 추가되거나 사라지는 현상이 발생합니다.
[4] SERIALIZABLE
한 트랜젝션에서 사용하는 데이터를 다른 트랜잭션에서 접근 못하게 막습니다. 단순 select만으로도 트랜잭션이 커밋 될 때 까지 다른 트랜잭션의 접근이 불가합니다. 굉장히 안전하겠지만 동시성 성능을 매우 떨어집니다.
| Dirty Read | Non Repeatable Read | Read Phantom Read |
---|
Read Uncommitted | o | o | o |
Read Committed | x | o | o |
Repeatable Read | x | x | o |
Serializable | x | x | x |
6. Transaction Recovery이란
트랜잭션은 커밋, 롤백 연산을 사용합니다. 이때 사용자의 입력 실수, 과도한 시스템 자원 요구, OS 오류 등 외부 요인에 의해 각 연산에 문제가 발생할 수 있습니다. 이를 해결하기 위해 Redo & Undo 작업을 수행합니다.
두 작업을 위해서는 작업 과정을 기억해야 되고, Log에 기록합니다. Log는 전원이 끊겨도 데이터를 저장할 수 있는 보조 기억 장치에 저장되는 경우가 많습니다.
[1] REDO 작업
DB가 비정상적으로 종료될 때 로그의 'start'와 'commit' 기록있는 트랜잭션들의 작업을 다시 수행합니다. 즉 트랜잭션 실행을 성공적으로 종료하였으나 디스크에는 반영되지 않았을 경우 로그를 활용하여 재작업을 수행합니다.
[2] UNDO 작업
DB가 비정상적으로 종료될 때 로그의 'start'는 있지만 완료를 나타내는 'commit' 기록이 없는 트랜잭션 작업을 원복합니다. 즉, 이전 디스크 상태로 원복합니다.
7. Transaction Recovery
[1] 지연 갱신
트랜잭션 커밋 전까지 DB에 기록하지 않고, Commit 이후 데이터를 반영합니다.
- Undo : Commit 이전에 DB에 기록하지 않아 작업이 필요없습니다.
- Redo : Commit 이후, 오류 발생시 로그를 참조하여 변경 데이터로 DB에 반영합니다.
[2] 즉시 갱신
트랜잭션 수행 도중 변경 내용을 즉시 로그와 & DB에 기록합니다.
- Undo : 커밋 이전 데이터를 갱신하기 때문에 문제시 Undo 작업을 수행합니다.
- Redo : 커밋 이전 데이터 변경 값이 디스크에 잘 들어갔는지 모르기 때문에 Redo 연산 또한 필요합니다.
[3] 체크 포인트
회복시 로그 파일 정보를 모두 비교하며 이미 디스크에 정상적으로 반영된 부분에 Undo, Redo 작업을 수행했습니다. 이러한 불필요한 연산을 줄이고자 Check Point가 도입됬습니다. 즉, 체크 포인트 이전에 수행된 결과는 신경쓰지 않고 이후 값들에 Undo, Redo 작업을 수행합니다.
아래 사진과 같이 에러가 나왔을 때 커밋을 이미 했다면 체크포인트 이후에 Redo 작업을, 커밋을 수행하지 않았다면 체크 포인트 이후에 Undo 작업을 수행합니다.
[4] 그림자 페이징 기법
트랜잭션이 실행되는 동안 로그를 사용하지 않고 두개의 페이지 테이블을 이용합니다. 트랜잭션에 의해 변경된 데이터는 현재 페이지 테이블에만 변경이됩니다. 만약 중간에 문제가 생겨 UNDO 작업을 수행한다면 그림자 페이지 테이블을 참조합니다. 로그 레코드를 유지할 필요는 없지만, 많은 페이지의 I/O 연산 작업으로 트랜잭션 처리 비용이 많습니다.