
트랜잭션과 지속성
트랜잭션의 원칙 중 Durability를 떠올려보면, 일단 커밋이 되면 DB는 반드시 데이터를 보장해야한다.
그렇다면 단순히 변경된 데이터를 바로바로 디스크에 저장하면 될까? -> 이렇게 하면 문제가 발생한다.
물리 디스크는 I/O 비용이 매우 높다
실제 데이터가 저장되는 디스크는 I/O 비용이 매우높다 (속도가 느리다).
즉, 데이터의 첫 시작점을 찾는데 너무 오래 걸리고, 대량의 데이터를 한번에 저장하게 되면 커밋하는 시간이 매우 길어진다.
처리 속도가 느려지면 동시 요청을 처리할 수 있는 능력이 매우 떨어지기 때문에, MySQL의 InnoDB는 WAL(Write- Ahead Logging)이라는 방식을 사용한다.
Write - Ahead Logging
WAL 방식은 Redo Log 와 Undo Log로 동작하는데, 그 방식은 다음과 같다.
Redo Log
1. 먼저 SQL로 데이터를 Update 하게 되면 디스크에 바로 반영하지 않고 Redo Log에 기록한다.
2. Commit 실행시 모아두었던 Redo Log를 보고 디스크에 정식적으로 반영한다.
2-2. 이때, 시스템이 중간에 다운 되어도 Redo Log가 살아 있다면 다시 데이터를 복구할 수 있다.
3. 데이터가 모두 반영되면 Redo Log를 삭제한다.
Undo Log
1. SQL로 업데이트 실행을 하게 되면, 기존의 데이터를 Undo Log로 저장해둔다.(기존 데이터 백업)
2. 이때 Rollback을 때리게 되면 해당 Undo Log를 보고 기존 상태로 복구 할 수 있다.
2-2. 만약 Commit 하게 되면 Undo Log는 필요가 없어지므로, 삭제한다.
정리하자면, 우리가 데이터를 변경하고자 하여 Update 문을 실행하게 되면 해당 변경 내용은 곧장 디스크에 반영되는 것이 아닌 Redo Log 라는 단위로 변경을 예정한다. 또한, 이때 Undo Log로 이전 데이터를 백업해둔다.
이후 변경사항을 Commit 하게 되면 Redo Log의 변경 사항을 모두 반영하고 Undo Log을 삭제하고, Rollback하게 되면 Redo Log 들이 삭제 되고 Undo Log의 기존 데이터들이 다시 반영되게 된다.
Redo / Undo Log와 격리성 레벨
1. Read Uncommitted
Read Uncommitted 방식은 트랜잭션이 수정한 데이터를 즉시 반영하는 방식이다.
즉, 다른 트랜잭션도 커밋하지 않는 변경 사항을 볼 수 있게 된다. 그럼 아마 Redo / Undo 로그가 다음과 같이 작동할 것이다.
1. txA가 트랜잭션 시작 -> 데이터A Update 시도 (아직 커밋 / 롤백 X)
2. 해당 변경 사항 Redo Log에 저장
3. txB도 데이터A 접근 시도 -> Redo Log를 참조하여 커밋되지 않은 데이터를 읽게 됨
2. Read Commited
Read Commited는 커밋된 최신 데이터를 보여주는 격리 수준이다.
그래서 반드시 트랜잭션이 조회 돌 때마다 최신 Commit 된 데이터를 가져와야한다.
이때는 Redo / Undo Log가 어떻게 작용하는지 보자.
1. txA가 데이터 Update -> 기존 데이터는 Redo Log에 백업됨 , 변경 시도 데이터는 Redo Log에 저장
2. txB가 데이터 조회시 txA는 아직 커밋하지 않았기 때문에 해당 레코드의 Undo Log, 즉 변경 전 기존 데이터를 읽어오게 됨
3. 만약 txA가 커밋을 하게 되면 이후 txB는 조회시 커밋된 최신 데이터 조회
3. Repeatable Read
Reapeatable Read는 트랜잭션이 끝날 때까지 동일한 데이터를 조회하도록 보장하는 격리 수준이다.
이를 위해 트랜잭션 시작시, Undo Log의 데이터를 유지하면서 같은 결과를 반환한다.
즉, Undo Log를 활용하여 처음 조회한 데이터를 계속 유지한다.
1. txA가 조회시, 해당 시점의 데이터를 Undo Log에 저장한다.
2. 이후 txA가 다시 같은 데이터를 조회 해도, 실제 레코드의 데이터를 읽는 것이 아닌 Undo Log에서 동일한 결과 값을 반환 받게 된다.
3. txB가 데이터를 변경하고 Commit 하게 되더라도, 현재 트랜잭션은 여전히 Undo Log에서 데이터를 읽고 있기 때문에, 과거의 일관된 데이터를 조회하게 된다.
MVCC == Repeatable Read에서 Undo Log가 관리 되는 방법
해당 격리성 레벨에서 Undo Log는 연동된 실제 레코드에서 조회 할까? 답은 아니다.
각각의 트랜잭션은 데이터를 Select 하는 순간의 값을 Undo 로그에 각자 "독립적"으로 유지한다.
즉, 각 트랜잭션은 각자의 버전으로 데이터가 존재하게 된다. 이게 바로 MVCC (Multi Version Concurreny Control) 방식이다.
MVCC 방식은 데이터베이스에서 트랜잭션이 동시에 실행 될 때, 각 트랜잭션이 자신만의 독집적인 데이터 버전을 볼 수 있도록 해주는 기술이다. 이때, 각 트랜잭션만의 독립적 Undo Log를 활용하여 자신이 조회하기 시작했던 순간의 데이터 버전을 유지할 수 있다.
그러나 트랜잭션의 개수가 많아지게 되면, 하나의 데이터에 대해 무수히 많은 버전이 생기게 된다. 즉, 이때 Undo Log가 많이 쌓이게 되며 메모리와 저장공간의 부담이 커지게 된다.
따라서 긴 트랜잭션은 지양하고, 짧은 트랜잭션을 지향 해야한다. (대량 삭제 같은 작업)
4. Serializable
가장 강력한 수준이며 완벽한 데이터 정합성을 보장한다.
1. txA가 조회시, 해당 레코드에 락이 걸린다.
2. 그래서 txB가 데이터를 수정하려고 하면 락이 풀릴 때까지 Wait 해야한다.
'우리 같이 백엔드 하자 > Transaction & Lock' 카테고리의 다른 글
| 트랜잭션&락 1편 - All Or Nothing / ACID (0) | 2025.12.22 |
|---|---|
| MySQL 트랜잭션 격리 수준 (Isolation Level) (0) | 2025.09.04 |