트랜잭션이란 DB에서 하나의 논리적 기능을 수행하기 위한 작업의 단위를 의미합니다.
논리적인 기능의 예시로 계좌이체라는 기능을 살펴봅시다.
A계좌에서 B계좌로 500만원을 계좌이체를 한다고 가정하겠습니다.
계좌이체과정
1. A계좌 잔액 조회(A계좌 잔액 : 500만원)
2. A계좌에서 500만원 출금(A계좌 잔액 -500 만원)
3. B계좌 잔액 조회(B계좌 잔액 : 0 만원)
4. B계좌에 500만원 입금(B계좌 잔액 +500 만원)
계좌이체라는 논리적 기능을 수행하기 위해서는 1~4 번의 기능을 묶어서 하나의 작업처럼 실행을 합니다.
이러한 계좌이체는 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위인 트랜잭션의 한 예시입니다.
데이터를 저장할 때 파일을 사용해도 되는데 굳이 DB를 사용하는 이유는 무엇일까요?
잠시 DB를 사용하지 않고, 파일(.txt 등)을 이용해서 계좌이체라는 작업의 단위를 우리가 직접 구현한다고 생각해봅시다.
직접 계좌이체를 구현하다보면 다음과 같은 불안한 생각들이 들 수 있습니다.
- "1~4번 과정 중에 하나라도 실패하면 어떡하지?"
- "A계좌의 돈이 500만원보다 적은데 500만원 이체를 하면 어떡하지?"
- "A계좌에서 B계좌로 돈을 이체하는 중에 A계좌에서 출금이 일어나면 어떡하지?"
- "계좌이체를 성공(커밋)했는데 갑자기 시스템에 오류가 발생하면 어떡하지?"(= "계좌이체를 성공하기 전에 갑자기 시스템 오류가 발생하면 어떡하지?")
이런 불안 요소들을 전부 제거하고 안전한 계좌이체를 구현해야 합니다.
다행스럽게도 DB에서는 불안한 생각들을 해소할 수 있도록 트랜잭션을 지원하고 있습니다.
앞서 트랜잭션은 작업의 단위라고 했는데, 이런 작업의 단위는 ACID를 지원해야 합니다.
ACID란 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질을 말합니다.
ACID
원자성 (Atomicity)
일관성 (Consistency)
격리성 (Isolation)
지속성 (Durability)
뭔가 어려운 것처럼 보이지만, 이것들은 결국 계좌이체를 직접 구현하려 했을 때 든 의문에 대한 대답들입니다.
"1~4번 과정 중에 하나라도 실패하면 어떡하지?"
원자성 (Atomicity)은 트랜잭션 내의 작업이 모두 성공하거나 모두 실패해야 하는 것을 말합니다. (All or Noting)
"500만원을 계좌이체를 하는데 A계좌에 출금(1~3번 과정)을 하는 것을 성공하고, B계좌에 입금(4번 과정)하는 것을 실패했다"고 가정해봅시다.
시작 잔고: A계좌 500만원 | B계좌 0 만원
1~3번 성공 : A계좌 0 만원 | B계좌 0 만원
4번 실패 : 실패했다!
계좌이체 이전 : A계좌 500 만원 | B계좌 0 만원
계좌이체 이후 : A계좌 0 만원 | B계좌 0 만원
위 상황에서는 계좌이체를 한 이후에 500만원은 사라지고 A,B계좌 모두 0원이 되었습니다.
만약 3~4번 과정이 성공하고, 1~2번 과정이 실패한다면 A,B계좌 모두 500만원이 있을 것입니다.
이런 상황들은 우리가 의도한 상황이 아닙니다.
즉 계좌이체라는 작업의 단위에서는 1~4번 과정들이 전부 성공하거나, 전부 실패해야 합니다.
DB의 트랜잭션은 트랜잭션 내의 작업이 모두 성공하거나 모두 실패하도록 원자성을 지원하고 있습니다.
"A계좌의 돈이 500만원보다 적은데 500만원 이체를 하면 어떡하지?"
(유사한 의문)"사용자가 qwe만원(숫자가 아닌 문자) 입금한다고 하면 어떡하지?"
일관성 (Consistency)은 데이터베이스의 상태가 일관되어야 한다는 것을 말합니다.
"A계좌에 450만원이 있는데 B계좌로 500만원을 이체한다"고 가정해봅시다. 마이너스 통장은 없다고 가정합니다.
시작 잔고: A계좌 450만원 | B계좌 0 만원
= 계좌이체 진행 =
이후 잔고: A계좌 -50만원 | B계좌 500 만원
다른 상황을 살펴봅시다.
사용자가 잘못 입력하여 A계좌에 숫자가 아닌 문자인 qwe만원을 입금하려 한다면 어떻게 해야 할까요?
A계좌의 잔고를 qwe 만원이라고 저장해야 할까요?
앞서 살펴본 두 상황은 모두 우리가 의도한 상황이 아닙니다.
마이너스 통장은 없다고 생각했고, 계좌의 돈은 숫자만 가능합니다.
DB의 트랜잭션은 계좌이체를 진행한 이후에도 DB의 제약이나 규칙을 만족할 수 있도록 일관성을 지원하고 있습니다.
"A계좌에서 B계좌로 돈을 이체하는 중에 A계좌에서 출금이 일어나면 어떡하지?"
격리성(Isolation)은 트랜잭션 수행 시 서로(다른 트랜잭션이) 끼어들지 못하는 것을 말합니다.
"500만원이 있는 A계좌에서 B계좌로 500만원 계좌이체를 진행하는 도중에 A계좌에서 100만원 출금이 발생했다"고 가정해봅시다.
(A계좌를 위주로 살펴봅니다.)
A -> B 500만원 이체 A계좌 100만원 출금 A계좌 잔액 조회(A계좌 잔액 : 500만원) A계좌 잔액 조회(A계좌 잔액 : 500만원) A계좌 잔액 : 500만원 - 100만원 출금 성공! A계좌 잔액 : 500만원 - 500만원 ... 이체 성공!
원래대로라면 A계좌에는 돈이 500만원 밖에 없기 때문에 계좌이체와 출금을 모두 수행할 수 없습니다.
하지만 위 상황에서는 성공해버려서 100만원이라는 새로운 돈이 생기게 되었습니다.
이렇게 어떤 트랜잭션(A -> B 500만원 이체)이 작업을 수행할 때 다른 트랜잭션(A계좌 100만원 출금)이 끼어들 수 없도록 만들어야 합니다.
DB의 트랜잭션은 트랜잭션 작업 수행 시에 격리되어 다른 트랜잭션이 끼어들 수 없도록 격리성을 지원하고 있습니다.
격리성은 DB의 성능과 연관되는 중요한 부분입니다.
격리성에 대한 자세한 내용은 다음 글에서 다루겠습니다.
"계좌이체를 성공(커밋)했는데 갑자기 시스템에 오류가 발생하면 어떡하지?"(= "계좌이체를 성공하기 전에 갑자기 시스템 오류가 발생하면 어떡하지?")
지속성(Durability)은 성공적으로 수행된 트랜잭션은 영원히 반영되어야 하는 것을 의미합니다.
만약 계좌이체를 성공했는데 시스템에 오류가 생겼다면 어떻게 하는 것이 좋을까요?
당연히 계좌이체라는 작업을 성공했다면, 시스템 내에 저장이 되어야 합니다.
만약 계좌이체를 시도하는 중 시스템에 오류가 생겼다면 어떻게 하는 것이 좋을까요?
해당 이체는 실패로 돌아가야 합니다.
DB의 트랜잭션은 성공적으로 수행된 트랜잭션은 영원히 반영되어야 하는 지속성을 지원하고 있습니다.
"모든 DB는 ACID를 지원하나?"에 대한 답은 "아니오"입니다.
MySQL, Oracle, PostgreSQL 등의 RDBMS는 ACID를 강력하게 지원하는 대표적인 예시입니다. 이러한 RDBMS에서는 데이터 일관성을 중시하고 트랜잭션을 원자적이고 일관적으로 처리합니다.
하지만 MongoDB, Redis 등의 NoSQL DBMS는 BASE를 지원합니다.
BASE란 데이터 일관성보다 가용성과 확장성을 강조하는 특성을 말합니다. 데이터 일관성은 시간이 지남에 따라 조정되고, 엄격한 ACID 특성보다 유연한 방식으로 데이터를 다룹니다.
기본적인 가용성 (Basically Avaliable)
소프트 상태 (Soft State)
결과적 일관성 (Eventually Consistent)
해당 글은 ACID에 대한 글이기 때문에 BASE에 대해 자세하게 다루진 않고 차이를 이해하실 정도로만 설명합니다.
ACID를 지원하는 DB가 있고 BASE를 지원하는 DB가 있는데 어떤 상황에 DB를 사용해야 할까요?
은행 시스템과, 소셜 미디어 피드 시스템을 생각해봅시다.
은행 시스템에서는 출금, 입금, 계좌이체, 잔액 갱신 등등이 모두 하나의 원자처럼 처리되어야 하고, 격리되어 처리되어야 합니다.
이런 시스템의 경우 ACID를 지원하는 RDBMS를 사용하는 것이 알맞을 것입니다.
많은 사용자들이 몰리는 소셜 미디어 피드 시스템에서는 모든 데이터가 즉시 일관성을 가져야 하는 것보다 사용자에게 빠른 응답과 가용성을 제공하는 것이 중요할 것입니다.
따라서 BASE를 지원하는 NoSQL DBMS를 사용하는 것이 알맞을 것입니다.
이렇게 주어진 상황에 따라서 알맞은 DB를 선택해서 사용하면 됩니다.
인프런 - CS 지식의 정석
https://ko.wikipedia.org/wiki/ACID
https://hanamon.kr/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%9D%98-acid-%EC%84%B1%EC%A7%88/