seegongsik
데이터

어떻게 동시에 써도 안 꼬이게, 트랜잭션

친구에게 만 원을 보낸다고 하자. 내 잔액에서 만 원을 빼고 친구 잔액에 만 원을 더해야 한다. 그런데 빼기는 끝났는데 더하기 직전에 전원이 꺼진다면? 내 돈은 빠져나갔는데 친구는 한 푼도 받지 못한다. 이런 사고를 막으려고 여러 고침을 한 덩어리로 묶어, 전부 되거나 전부 안 되게 하는 방법이 트랜잭션이에요.

01

이체는 빼기와 더하기가 한 짝이에요

앞 레슨에서는 정보를 한 곳에만 두도록 표를 나눴다. 그래도 고칠 곳이 하나로 끝나지 않는 일이 있다. 계좌 이체가 그렇다. 내 잔액에서 돈을 빼고, 받는 사람 잔액에 같은 만큼을 더해야 한다.
이 둘은 떼어 놓을 수 없는 짝이에요. 하나만 되면 돈이 사라지거나 없던 돈이 생긴다. 아래에서 두 고침을 따로따로 해 보자.

내 잔액30
친구 잔액10
둘의 합40
두 버튼을 하나씩 따로 눌러요

빼기와 더하기를 따로 눌러 보자. 하나만 누르면 둘의 합이 달라져, 돈이 사라지거나 없던 돈이 생겨요.

빼기만 누르면 내 돈이 사라지고, 더하기만 누르면 없던 돈이 생긴다. 어느 쪽이든 둘의 합이 처음과 달라져요. 이체는 돈을 옮기는 일이니 합은 그대로여야 한다.
위험한 곳은 빼기와 더하기 사이의 짧은 틈이다. 그 틈에 전원이 나가거나 프로그램이 멈추면 장부가 어긋난 채로 남는다. 그래서 두 고침을 하나로 묶는 방법이 필요하다.

02

전부 되거나, 전부 안 되거나

방법은 단순하다. 빼기와 더하기를 한 덩어리로 묶고, 이 덩어리를 트랜잭션이라고 부른다. 덩어리 안의 고침은 모두 임시로 둔다.
전부 준비되면 확정해서 한꺼번에 진짜로 반영하고, 하나라도 안 되면 전부 취소해요. 확정하는 것을 커밋, 취소해 되돌리는 것을 롤백이라고 한다. 이렇게 하면 절반만 반영된 상태는 생기지 않고, 다른 사람 눈에도 중간 상태는 보이지 않는다. 이 성질을 원자성이라고 해요. 더 쪼갤 수 없는 한 덩어리라는 뜻이다.

한 묶음 (트랜잭션)
빼기 담기
더하기 담기
내 잔액30
친구 잔액10
두 고침을 묶음에 담아요

두 고침을 한 묶음에 담아 보자. 둘 다 담겨야 확정할 수 있고, 취소하면 담은 고침이 둘 다 사라져요.

확정하면 두 잔액이 함께 바뀌어 합이 그대로이고, 취소하면 둘 다 깨끗이 사라진다. 어느 쪽이든 장부는 어긋나지 않아요. 묶음으로 다뤘을 뿐인데 위험한 틈이 없어졌다.
그런데 묶음 안에서 일하는 도중에 정말로 전원이 꺼지면 어떻게 될까? 임시로 둔 고침은 어떻게 처리될까?

03

끊겨도 통째로 되돌린다

데이터베이스는 고치기 전에 무엇을 어떻게 바꿀지 로그라는 기록에 먼저 적어 둔다. 시작 전 상태로 돌아갈 수 있는 정보도 함께 남긴다.
그래서 도중에 전원이 꺼져도, 다시 켜졌을 때 로그를 읽으면 끝나지 못한 묶음을 알아낼 수 있어요. 그러면 절반만 남기지 않고 그 묶음을 시작 전 상태로 통째로 되돌린다. 반대로 확정까지 끝난 묶음은 전원이 꺼진 뒤에도 그대로 살아 있다. 확정된 결과가 사라지지 않는 이 성질을 지속성이라고 한다.

시작 전 상태 (따로 적어 둠)30 / 10
내 잔액30
친구 잔액10
한 단계 진행한 뒤 전원 끊김을 눌러요

한 단계 진행한 뒤 전원 끊김을 눌러 보자. 절반만 남기지 않고 따로 적어 둔 시작 전 상태로 통째로 되돌아가요.

끊겼는데도 장부는 멀쩡하다. 빼기만 반영된 엉망인 상태 대신 깨끗하게 시작 전으로 돌아갔다. 이것이 롤백이에요.
실패해도 흔적이 남지 않으니 처음부터 다시 하면 된다. 이체 전에도 후에도 장부의 규칙, 이를테면 두 잔액의 합이 그대로라는 규칙이 지켜진다. 이것을 일관성이라고 부른다. 그런데 여러 사람이 같은 잔액을 동시에 고치려 하면 어떻게 될까?

04

동시에 와도 차례로 처리해요

운영체제 영역에서 본 경쟁 상태를 떠올려 보자. 둘이 같은 자원을 동시에 건드리면 결과가 꼬였다. 잔액도 같아요.
두 사람이 같은 잔액을 동시에 읽고 각자 더한 값을 써 넣으면, 나중에 쓴 사람이 앞사람의 결과를 덮어쓴다. 한 사람의 변경이 통째로 사라지는 것이다. 이것을 갱신 손실이라고 한다. 그래서 데이터베이스는 잠금 같은 장치로, 같은 줄을 고치는 묶음들을 한 번에 하나씩 차례로 처리한다.

사람 X (+5)+5
사람 Y (+8)+8
같은 잔액100
동시에 보내면 한쪽이 덮어써요

두 사람을 동시에 보내 보자. 그대로 두면 나중에 쓴 쪽이 덮어써 한쪽 변경이 사라지고, 차례로 막으면 둘 다 더해져요.

그대로 두니 한쪽의 변경이 사라졌고, 차례로 처리하니 둘 다 반영됐다. 동시에 와도 잠깐 줄을 세워, 한 묶음이 끝난 뒤에 다음 묶음을 받는다.
이렇게 동시에 돌아가는 묶음들이 서로의 중간 상태를 보지 못하게 떼어 놓는 성질을 격리성이라고 해요. 다만 모두를 엄격하게 줄 세우면 느려지기 때문에, 실제 데이터베이스는 얼마나 엄격하게 떼어 놓을지 단계를 골라 쓰게 한다.

05

정리

정리하면 이렇다. 함께 바뀌어야 하는 고침들을 한 묶음으로 묶어 전부 되거나 전부 안 되게 한다. 도중에 끊기면 로그를 보고 시작 전으로 통째로 되돌리고, 확정된 결과는 전원이 꺼져도 남는다.
여러 묶음이 같은 곳을 동시에 고치려 하면 차례로 줄을 세워 덮어쓰기를 막아요. 원자성, 일관성, 격리성, 지속성, 머리글자를 따서 ACID라고 부르는 이 네 가지 약속이 트랜잭션이다.

핵심 4가지를 차례로 눌러요
아래 핵심을 위에서부터 차례로 눌러요

핵심을 차례로 눌러 되짚어 보자. (이체는 짝 → 전부 아니면 전무 → 어긋나면 롤백 → 동시에도 안 꼬임)

이제 데이터를 안전하게 바꾸는 약속을 알았다. 돈이 사라지던 틈도, 전원이 꺼져 절반만 남던 사고도, 동시에 고쳐 덮어쓰던 혼란도 한 묶음이라는 생각으로 막을 수 있어요.
안전하게 바꾸는 법 다음은 빠르게 읽는 법이다. 같은 데이터를 자꾸 데이터베이스까지 가서 꺼내는 대신 가까운 곳에 사본을 두는 방법을 다음 레슨 캐시에서 다룬다.

한 줄 정리트랜잭션은 함께 바뀌어야 하는 여러 고침을 한 묶음으로 다뤄, 전부 되거나 전부 안 되게 하는 방법이다. 계좌 이체처럼 빼기와 더하기가 짝일 때는 둘 다 준비돼야 확정하고, 하나라도 안 되면 전부 취소해요. 도중에 전원이 꺼져도 데이터베이스는 미리 적어 둔 로그로 끝나지 못한 묶음을 찾아 시작 전 상태로 통째로 되돌리는데, 이것을 롤백이라고 한다. 확정된 결과는 전원이 꺼진 뒤에도 남는다. 여러 사람이 같은 잔액을 동시에 고치려 하면 차례로 처리해 서로 덮어쓰지 않게 막아요. 원자성, 일관성, 격리성, 지속성을 묶어 ACID라고 부르며, 이 네 가지가 트랜잭션의 약속이다.
← 데이터
이 페이지가 도움 됐다면 후원하기