온라인 트랜잭션 처리
고친 사람 github-actions[bot]
온라인 트랜잭션 처리는 사용자가 기다리는 동안 데이터를 바로 읽고 고쳐서 답하는 일입니다. 쇼핑몰에서 주문 버튼을 누르면 재고가 하나 줄고 주문 한 건이 저장되는 것이 이 일입니다. 이런 요청은 많은 사용자에게서 한꺼번에 몰립니다. 그래도 하나하나가 빠르고 어긋남 없이 끝나야 합니다. 서비스가 날마다 쓰는 데이터베이스가 맡는 일이 대개 이것입니다.
쉽고 빠른 이해
사용자 요청 하나가 올 때마다 데이터 몇 건을 바로 읽고 고치는 일입니다. 주문 하나가 들어오면 재고 한 줄을 줄이고 주문 한 줄을 적습니다.
이 처리가 느리거나 어긋나면 서비스가 바로 망가집니다. 손님은 결제 화면 앞에서 기다립니다. 하나 남은 물건이 두 사람에게 팔립니다.
- 요청이 오면 필요한 행 몇 개만 곧장 찾아갑니다
- 읽기와 쓰기를 한 묶음으로 처리해 전부 반영하거나 전부 취소합니다
- 같은 행을 동시에 고치려는 요청은 하나씩 차례로 통과시킵니다
대가는 큰 집계에 약하다는 것입니다. 데이터를 한 건씩 빠르게 다루도록 담아 두었기 때문입니다. 그래서 몇 달치를 모두 훑는 분석은 느립니다. 그동안 다른 요청까지 느려집니다. 그래서 분석은 데이터를 다른 저장소로 옮겨서 따로 합니다.
상세
편의점 계산대를 떠올리면 됩니다. 손님은 줄을 서 있습니다. 한 사람을 계산하는 데는 몇 초면 끝납니다. 바코드를 찍을 때마다 그 물건 하나의 기록만 고칩니다.
가게의 한 달 매출을 계산대 앞에서 따지는 사람은 없습니다. 그 일은 가게 문을 닫은 뒤 사무실에서 합니다.
온라인 트랜잭션 처리는 OLTP(Online Transaction Processing, 온라인 트랜잭션 처리)라고 줄여 부릅니다. 사용자 요청마다 적은 양의 데이터를 읽고 고치는 짧은 작업을 아주 많이 처리하는 방식입니다. 회원 가입, 주문, 결제, 게시글 작성이 그 예입니다. 백엔드 API(Application Programming Interface, 애플리케이션 프로그래밍 인터페이스) 하나가 데이터베이스에 하는 일은 대부분 여기에 듭니다.
이름에 든 두 낱말
이름의 두 낱말은 이 일이 무엇과 다른지를 알려 줍니다. 하나씩 보겠습니다.
온라인은 인터넷에 붙어 있다는 뜻이 아닙니다. 요청이 들어오는 즉시 처리해서 곧바로 답한다는 뜻입니다. 반대편은 배치 처리입니다. 일을 모아 두었다가 정해 둔 때에 한꺼번에 처리하는 방식입니다. 밤마다 하루치 정산을 돌리는 작업이 배치 처리의 흔한 예입니다.
트랜잭션은 여러 읽기와 쓰기를 한 묶음으로 처리하는 단위입니다. 묶음 안의 일은 전부 반영되거나 전부 취소됩니다. 주문에서 재고를 줄이는 쓰기와 주문을 적는 쓰기는 한 묶음이어야 합니다. 하나만 반영되면 재고는 줄었는데 주문은 없는 상태가 남기 때문입니다.
주문 한 건의 처리
OLTP 작업이 어떻게 생겼는지 주문 한 건으로 보겠습니다. 상품 7번의 재고가 3개 남은 상태에서 한 개를 주문합니다. 데이터베이스에 내리는 명령을 SQL(Structured Query Language, 구조화 질의 언어)로 적으면 이렇습니다.
BEGIN;
SELECT stock FROM item WHERE id=7; -- 3
UPDATE item SET stock = stock - 1
WHERE id = 7;
INSERT INTO orders (item_id, qty)
VALUES (7, 1);
COMMIT;
SELECT stock FROM item WHERE id=7; -- 2
BEGIN 과 COMMIT 사이가 한 트랜잭션입니다. 실제 서비스라면 첫 SELECT 로 읽은 재고가 0 일 때 주문을 거절하고 트랜잭션을 취소합니다. 여기서는 3 이라 그대로 이어 갑니다.
이 작업이 건드린 행은 상품 한 줄과 주문 한 줄뿐입니다. 마지막 조회가 2를 돌려주는 것은 두 쓰기가 함께 확정됐다는 뜻입니다.
상품 번호로 행을 곧장 찾아가는 데는 인덱스를 씁니다. 인덱스는 책 뒤의 찾아보기처럼 값을 주면 행이 어디 있는지 바로 알려 주는 구조입니다. 그래서 테이블에 행이 아주 많아도 한 건을 찾는 일은 금방 끝납니다.
행마다 붙는 고유 번호를 기본 키라고 합니다. 앞의 SQL 에서 상품을 가리킨 id 가 이런 번호입니다. 기본 키에는 대개 인덱스가 함께 만들어집니다. 그래서 기본 키로 한 건을 찾는 일은 따로 준비하지 않아도 빠릅니다.
OLTP 작업의 생김새
주문 한 건에서 본 모습은 OLTP 작업 전반에 걸쳐 되풀이됩니다. 다섯 가지로 간추리면 이렇습니다.
| 특징 | 모습 |
|---|---|
| 한 번에 건드리는 양 | 행 몇 개 |
| 행을 찾는 방법 | 기본 키나 인덱스로 찾아간다 |
| 읽기와 쓰기 | 섞여 있고 쓰기가 잦다 |
| 요청 수 | 많고 동시에 몰린다 |
| 응답 시간 | 짧아야 한다. 사용자가 화면 앞에서 기다린다 |
이 특징이 OLTP 시스템을 재는 잣대도 정합니다. 초당 몇 건을 끝내나는 TPS(Transactions Per Second, 초당 트랜잭션 수)로 잽니다.
한 건이 끝나기까지 얼마나 걸렸나는 응답 시간으로 잽니다. 사용자가 화면 앞에서 기다리는 시간이 바로 이것입니다.
동시에 몰리는 요청
OLTP 에서 가장 까다로운 일은 같은 행을 여러 요청이 동시에 고치는 경우입니다. 앞 절의 주문 SQL 을 두 요청이 동시에 돌린다고 하겠습니다. 이번에는 재고가 1개 남았습니다.
두 요청이 첫 SELECT 에서 모두 재고 1을 읽으면 둘 다 주문을 받아 줍니다. 물건은 하나인데 두 사람에게 팔린 셈입니다. 앞 절의 SQL 은 이렇게 겹치면 이중 판매를 막지 못합니다.
데이터베이스는 이런 겹침을 막는 장치를 갖고 있습니다. 대표가 잠금입니다. 한 트랜잭션이 행을 잠그면, 같은 행을 잠그려는 다른 트랜잭션은 앞 트랜잭션이 커밋하거나 취소할 때까지 기다립니다.
행을 고치는 UPDATE 는 그 행을 잠급니다. 그런데 앞 절의 SQL 은 잠그기 전에 SELECT 로 재고를 먼저 읽습니다. 그러니 읽는 순간부터 잠가야 합니다.
SELECT stock FROM item
WHERE id = 7 FOR UPDATE; -- 1
FOR UPDATE 는 읽으면서 그 행을 잠그라는 뜻입니다. 앞 절의 SQL 에서 첫 SELECT 를 이 줄로 바꾸면 두 주문은 아래처럼 차례로 지나갑니다.
sequenceDiagram
participant A as 주문 A
participant R as 재고 행
participant B as 주문 B
A->>R: 잠그고 1 을 읽는다
B->>R: 잠그려 한다
Note over B: A 가 끝날 때까지 기다린다
A->>R: 0 을 쓰고 커밋한다
B->>R: 잠그고 0 을 읽는다
Note over B: 재고가 없어 주문을 거절한다
주문 B 는 A 가 커밋할 때까지 기다립니다. 그래서 B 는 A 가 커밋한 뒤의 값인 0 을 읽습니다. 하나 남은 물건은 한 사람에게만 팔립니다.
기다림이 생기는 만큼 트랜잭션은 짧게 둡니다. 트랜잭션이 길면 잠금이 오래 이어집니다. 그동안 뒤에 선 요청이 모두 늦어집니다. 트랜잭션 안에서 외부 서비스를 부르지 않는 것도 같은 까닭입니다.
트랜잭션이 지키는 네 성질
지금까지 본 묶음과 잠금은 트랜잭션이 지키는 성질의 일부입니다. 데이터베이스는 트랜잭션마다 네 가지 성질을 지킵니다. 이 넷을 영어 머리글자로 묶어 ACID(Atomicity, Consistency, Isolation, Durability) 라고 부릅니다.
| 성질 | 뜻 | 이 문서의 장면 |
|---|---|---|
| 원자성 | 전부 반영되거나 전부 취소된다 | 재고 줄이기와 주문 적기가 함께 확정된다 |
| 일관성 | 데이터가 정해 둔 규칙을 어기지 않는다 | 재고가 0 아래로 내려가지 않는다 |
| 격리성 | 동시에 도는 트랜잭션이 서로 끼어들지 않는다 | 주문 B 가 A 의 커밋을 기다린다 |
| 지속성 | 커밋한 결과는 장애 뒤에도 남는다 | 커밋한 주문은 서버가 다시 켜져도 남는다 |
일관성의 규칙은 서비스를 만드는 쪽이 정합니다. 「재고는 0 아래로 내려가지 않는다」처럼 데이터가 늘 지켜야 하는 조건입니다. OLTP 데이터베이스는 이 네 성질을 기본으로 지킵니다.
데이터를 담는 방식
OLTP 데이터베이스는 데이터를 담는 방식도 한 건씩 다루기 좋게 고릅니다. 두 가지가 두드러집니다.
첫째는 정규화입니다. 같은 사실을 한 곳에만 적도록 테이블을 나누는 설계입니다. 고객 주소는 고객 테이블에만 둡니다. 주문 테이블에는 고객 번호만 적습니다. 주소가 바뀌면 고객 행 하나만 고치면 됩니다. 쓰기가 잦은 OLTP 에서는 고칠 곳이 적을수록 빠릅니다. 어긋날 일도 적습니다.
둘째는 행 지향 저장입니다. 한 행의 값들을 디스크에 붙여서 저장하는 방식입니다. 주문 한 건을 읽거나 쓸 때는 그 행의 열을 한 번에 다룹니다. 그래서 한 건 단위 작업에 잘 맞습니다. 반대로 열 하나만 아주 많이 읽는 집계에서는 쓰지 않을 열까지 읽어야 해서 불리합니다.
분석 처리와 견주기
OLTP 와 짝을 이루는 말이 온라인 분석 처리입니다. OLAP(Online Analytical Processing, 온라인 분석 처리)라고 줄여 부릅니다. 쌓인 데이터를 넓게 훑어 합계와 추세를 내는 일입니다. 「지난 분기 지역별 매출」 같은 질문이 그렇습니다.
두 일은 데이터를 담는 방식부터 다릅니다. OLAP 쪽은 정규화와 반대로 테이블을 합쳐 둡니다. 분석할 때마다 여러 테이블을 잇지 않도록, 주문 행 옆에 고객 지역 같은 값을 미리 붙여 한 테이블에 두는 식입니다. 같은 값이 여러 행에 되풀이되지만 쓰기가 드물어서 감당할 만합니다.
저장 방식으로는 열 지향 저장이 흔합니다. 한 열의 값들을 디스크에 붙여 저장하는 방식입니다. 「매출 합계」를 낼 때 매출 열만 읽으면 되어서 넓게 훑는 집계에 잘 맞습니다.
그 밖의 면에서도 두 일은 거의 반대쪽에 섭니다. 표로 견주면 이렇습니다.
| OLTP | OLAP | |
|---|---|---|
| 하는 일 | 서비스 요청을 처리한다 | 쌓인 데이터를 분석한다 |
| 한 번에 읽는 양 | 행 몇 개 | 아주 많은 행 |
| 쓰기 | 작고 잦다 | 드물고 크게 몰아서 넣는다 |
| 묻는 쪽 | 서비스 사용자 | 분석가 · 보고서 |
| 테이블 설계 | 정규화해 잘게 나눈다 | 미리 합쳐 둔다 |
| 저장 방식 | 행 지향이 흔하다 | 열 지향이 흔하다 |
OLTP 는 좁게 자주 다룹니다. OLAP 는 넓게 가끔 다룹니다. 한 저장 방식이 두 일에 다 맞기 어려운 까닭이 이 차이에 있습니다.
두 일을 따로 두는 까닭
분석 쿼리를 운영 데이터베이스에 바로 돌리면 문제가 생깁니다. 넓은 범위를 훑는 쿼리가 디스크와 프로세서를 오래 붙잡습니다. 그동안 주문과 결제 같은 짧은 요청까지 느려집니다.
그래서 흔히 데이터를 옮겨서 분석합니다. 옮겨 가는 곳은 분석용 저장소인 데이터 웨어하우스입니다. 운영 데이터베이스의 데이터를 주기적으로 꺼내 여기에 쌓습니다. 분석 쿼리와 보고서는 웨어하우스에서 돕니다.
옮기는 길에 데이터의 모양도 바꿉니다. 운영 쪽에 잘게 나눠 둔 테이블을 앞 절에서 본 것처럼 미리 합쳐 두는 것이 그 예입니다. 꺼내고 모양을 바꾸고 넣는 이 과정을 ETL(Extract-Transform-Load, 추출-변환-적재)이라고 부릅니다.
flowchart TD
U["사용자 요청"] --> O["운영 데이터베이스 · OLTP"]
O -->|"ETL · 주기적으로 옮긴다"| W["데이터 웨어하우스 · OLAP"]
W --> A["분석 쿼리 · 보고서"]
사용자 요청과 분석 쿼리는 서로 다른 저장소에 닿습니다. 그래서 분석이 무거워져도 서비스 응답은 영향을 덜 받습니다.
대가는 늦음입니다. 웨어하우스에는 마지막으로 옮긴 때까지의 데이터만 있습니다. 이 틈을 줄이려고 바뀐 행만 골라 바로바로 옮기기도 합니다. 이 방식을 변경 데이터 캡처라고 부릅니다.
쓰는 때와 다른 길을 고르는 때
서비스가 요청마다 데이터 몇 건을 읽고 고친다면 그 저장소는 OLTP 로 다룹니다. 회원, 주문, 결제, 재고처럼 틀리면 안 되고 곧바로 반영돼야 하는 데이터가 여기에 듭니다.
몇 달치를 모두 훑어 숫자를 내는 일은 OLTP 데이터베이스에 맡기지 않습니다. 매출 대시보드나 사용자 행동 분석이 그렇습니다. 이런 일은 데이터 웨어하우스 같은 분석용 저장소로 보냅니다.
두 일을 한 시스템에서 함께 처리하는 방식도 있습니다. 이런 시스템을 HTAP(Hybrid Transactional/Analytical Processing, 혼합 트랜잭션·분석 처리)라고 부릅니다. 옮기는 과정 없이 최신 데이터로 분석할 수 있습니다. 대신 한 시스템이 두 일의 부하를 함께 견뎌야 합니다.
관련 항목
온라인 트랜잭션 처리를 받치는 데이터베이스 기능
트랜잭션 · ACID · 잠금 · 격리 수준 · MVCC · 커밋 · 롤백 · 데이터베이스 인덱스 · 기본 키
온라인 트랜잭션 처리에 맞춘 데이터 설계
관계형 데이터베이스 · 정규화 · 외래 키 · 행 지향 저장 · 데이터 모델링 · SQL
온라인 트랜잭션 처리를 재는 지표
TPS · 응답 시간 · 지연 · 처리량 · TPC-C
온라인 트랜잭션 처리와 맞세워지는 처리 방식
온라인 분석 처리 · 배치 처리 · 스트리밍 처리 · HTAP · 열 지향 저장
운영 데이터를 분석 저장소로 옮기는 경로
데이터 웨어하우스 · ETL · ELT · 변경 데이터 캡처 · 데이터 레이크 · 운영 데이터 저장소 · 읽기 전용 복제본
동시 요청이 몰릴 때 터지는 문제
갱신 손실 · 데드락 · 락 경합 · 더티 리드 · 팬텀 읽기
온라인 트랜잭션 처리에 흔히 쓰는 데이터베이스
PostgreSQL · MySQL · Oracle · Microsoft SQL Server
온라인 트랜잭션 처리를 부르는 분야
데이터베이스 · 데이터 엔지니어링 · 백엔드 · 비즈니스 인텔리전스 · Apache Parquet
다른 이름: OLTP · Online Transaction Processing · 온라인 트랜잭션 프로세싱