
오늘 HN에서 "SQLite is all you need for durable workflows"가 377점 받고 올라왔다. 제목만 보면 또 흔한 "SQLite가 최고다" 류 떡밥인가 싶지만, durable workflow라는 키워드가 붙으면 얘기가 좀 다르다. 실무에서 Temporal이나 AWS Step Functions 같은 워크플로 엔진을 한 번이라도 운영해본 사람이면 "이걸 SQLite로?" 하는 의문이 바로 들 거다. 정리해보자.
왜 지금 이게 화제인가
먼저 durable workflow가 뭔지부터. 결제 처리, 주문 파이프라인, 이메일 발송 후 N일 뒤 리마인드 보내기 같은 여러 단계로 이루어지고, 중간에 프로세스가 죽어도 멈춘 지점부터 다시 이어가야 하는 작업을 말한다.
이걸 직접 짜본 사람은 안다. 그냥 함수 호출 이어붙이면 서버가 3번째 스텝에서 OOM으로 죽는 순간 끝장이다. 1, 2번 스텝은 이미 실행됐는데(예: 카드 승인 완료), 재시작하면 처음부터 다시 돌아 중복 결제가 난다. 그래서 나온 게 Temporal, Cadence, AWS Step Functions, Azure Durable Functions 같은 솔루션이다.
문제는 이 엔진들이 하나같이 인프라가 무겁다는 거다. Temporal만 해도 자체적으로 Cassandra나 PostgreSQL, Elasticsearch를 깔아야 하고, 워커 클러스터에 frontend/history/matching 서비스까지 띄워야 한다. 작은 팀이 "주문 처리 단계 5개를 안정적으로 굴리고 싶다"는 이유로 도입하기엔 운영 부담이 너무 크다. 여기서 "그냥 SQLite 하나로 안 되나?"라는 발상이 나온 거다.
핵심: durable execution의 원리와 SQLite의 역할
durable workflow의 핵심은 단순하다. 각 스텝의 실행 결과를 영속 저장소에 기록(append)하고, 재시작 시 그 기록을 리플레이해서 이미 끝난 스텝은 건너뛴다. 이걸 event sourcing 혹은 journaling이라 부른다.
의사코드로 보면 이렇다.
async def order_workflow(ctx, order_id):
# ctx.step()은 "이미 실행했으면 저장된 결과를 반환,
# 아니면 실행하고 결과를 DB에 기록"한다
payment = await ctx.step("charge", lambda: charge_card(order_id))
await ctx.step("reserve", lambda: reserve_stock(order_id))
await ctx.sleep("wait", timedelta(days=1)) # 1일 대기도 durable하게
await ctx.step("notify", lambda: send_email(order_id))
여기서 ctx.step이 마법의 핵심이다. 동작을 풀어보면:
charge스텝을 실행하기 전, DB에 "charge 시도 시작" 기록- 실제
charge_card실행 - 결과를 DB에 커밋. 여기까지가 하나의 트랜잭션
- 만약 2번과 3번 사이에 프로세스가 죽으면? 재시작 시 "charge가 완료 안 됨"으로 보고 재시도
- 이미 charge가 완료됐으면 저장된 결과를 그대로 반환하고 다음으로 넘어감
여기서 SQLite가 빛난다. 워크플로 상태와 스텝 실행 로그를 저장하는 게 결국 트랜잭션 보장되는 작은 KV/로그 저장소면 충분한데, SQLite가 정확히 그거다. WAL 모드 켜면 동시 읽기도 잘 버티고, 단일 파일이라 운영할 게 없다. 별도 DB 프로세스도, 네트워크 홉도 없다.
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL; -- durability vs 성능 트레이드오프, 뒤에서 설명
CREATE TABLE workflow_steps (
run_id TEXT NOT NULL,
step_id TEXT NOT NULL,
status TEXT NOT NULL, -- pending / completed / failed
result BLOB,
created_at INTEGER,
PRIMARY KEY (run_id, step_id)
);
비유하자면 Temporal이 "전기, 수도, 가스 다 끌어와야 하는 대형 공장"이라면, SQLite 기반은 "전기 콘센트 하나로 돌아가는 작업대"다. 처리량과 규모가 작업대 수준이면 공장을 지을 이유가 없다.
실무 관점: 도입 전에 반드시 따져야 할 것들
1. 워크플로 함수는 반드시 deterministic해야 한다
이건 SQLite든 Temporal이든 durable execution 모델의 공통 함정인데, 처음 쓰는 사람이 100% 밟는 지뢰다. 리플레이로 상태를 복원하기 때문에, 워크플로 함수 본문에서 datetime.now(), random(), 외부 API 직접 호출 같은 비결정적 코드를 쓰면 안 된다. 리플레이할 때마다 값이 달라져서 분기가 꼬인다.
현재 시각이 필요하면 ctx.now()처럼 엔진이 제공하는, 결과가 기록되는 함수를 써야 한다. 외부 호출은 전부 ctx.step()으로 감싸야 한다. 이 규칙을 모르고 짜면 "평소엔 잘 되는데 재시작하면 가끔 이상하게 동작하는" 최악의 디버깅 지옥에 빠진다.
2. SQLite의 동시성 한계 = 곧 처리량 천장
SQLite는 WAL 모드여도 쓰기는 한 번에 하나만 된다(single writer). durable workflow는 스텝마다 쓰기가 발생하므로, 초당 수천 건 이상의 워크플로 전이가 필요하면 SQLite는 병목이 된다. 단일 노드에서 초당 수백~수천 트랜잭션 수준이 현실적인 상한선으로 보인다(워크로드·디스크에 따라 크게 다름, 직접 벤치 필요).
반대로 말하면, 워크플로 전이가 초당 수십~수백 건 수준이고 단일 노드로 충분한 규모면 SQLite가 오히려 더 빠르고 단순하다. 네트워크 왕복이 없으니까.
3. 단일 노드 = SPOF, 그리고 수평 확장 불가
가장 큰 트레이드오프다. SQLite 파일은 한 머신에 묶여 있다. 그 노드가 죽으면 워크플로 처리가 멈춘다. Temporal이 무거운 이유 중 하나가 바로 이 HA(고가용성)와 수평 확장을 기본 제공하기 때문이다.
대응책으로는:
- EBS 같은 영속 볼륨 + 빠른 재기동으로 RTO를 줄인다 (active-passive)
- Litestream으로 S3에 실시간 백업해서 데이터 유실만 막는다 (복구는 수동)
- 정말 HA가 필요하면 이 패턴 자체가 부적합하다. 솔직하게 인정하고 다른 걸 써야 한다
4. synchronous 설정과 durability 트레이드오프
위 스니펫에서 synchronous = NORMAL로 했는데, 이건 OS 크래시(전원 차단 등) 시 마지막 트랜잭션 일부가 날아갈 수 있다. "durable"을 표방하면서 데이터 유실 가능성을 열어두는 건 모순이다. 금전 거래처럼 한 건도 잃으면 안 되는 워크로드면 synchronous = FULL로 가야 하고, 그만큼 쓰기 지연이 늘어난다. 무엇을 보장하고 싶은지부터 정하고 설정해야 한다.
대안 비교
- Temporal: 규모 크고 HA 필수, 전담 인프라 인력 있을 때. 오버스펙 주의.
- DBOS (PostgreSQL 기반): durable workflow를 Postgres 위에서. 이미 Postgres 쓰는 팀이면 SQLite보다 자연스러운 선택지일 수 있다.
- SQLite 기반: 단일 서비스, 소규모 팀, 운영 단순함이 최우선일 때.
- 그냥 메시지 큐 + 멱등 처리: 워크플로가 단순한 fan-out 수준이면 굳이 엔진 안 써도 된다.
정리
한 줄 요약: durable workflow의 본질은 "트랜잭션 가능한 스텝 로그 + 리플레이"이고, 규모가 단일 노드로 충분하면 그 저장소를 SQLite로 두는 게 운영상 가장 단순하다.
이런 사람에게 추천한다 — 스타트업/소규모 팀에서 결제·주문·예약 같은 다단계 작업을 안정적으로 굴려야 하는데, Temporal 클러스터 운영할 여력은 없는 경우. 반대로 초당 수천 건 이상 처리하거나 HA가 계약 조건인 환경이면 처음부터 무거운 엔진을 쓰는 게 맞다. "SQLite로 충분한가"는 결국 처리량과 가용성 요구사항이 단일 노드 안에 들어오느냐로 결정된다. 멋져 보여서가 아니라, 본인 워크로드 숫자를 먼저 재보고 고르자.
참고 자료
'Tech_News' 카테고리의 다른 글
| Postgres 하나로 Durable Workflow 짜기 — DBOS 방식이 실무에서 먹히는 이유 (0) | 2026.05.29 |
|---|
