무엇인가
TigerBeetle은 금융 거래 전용 분산 데이터베이스입니다. 스키마는 계정(Account)과 이체(Transfer) 둘뿐이고, 모든 이체는 한 계정에서 다른 계정으로 가치가 옮겨 간 기록, 곧 복식부기입니다. 이체는 불변이라 잘못된 이체는 고치지 않고 반대 방향 이체를 하나 더 적습니다. 2020년에 시작됐고 소스는 Zig 약 15만 줄로 Apache 2.0에 공개돼 있습니다.
그런데 이 항목의 주인공은 데이터베이스보다 그것을 검증하는 방법입니다. 분산 시스템의 버그는 고치기보다 재현하기가 어렵습니다. 스위치가 30초 이상했고 디스크가 재시도했고 시계가 어긋났던 그 순간을 다시 만들 수 없기 때문입니다. TigerBeetle은 세상을 통째로 가짜로 만들어 이 문제를 풉니다. 시간은 정수 카운터, 디스크는 메모리 배열, 네트워크는 큐, 난수는 씨앗 하나에서 뽑습니다. 그러면 실행 전체가 정수 하나로 결정되고, 그 정수만 적어 두면 누구의 노트북에서든 같은 우주가 되살아납니다. 이것이 결정론적 시뮬레이션 테스트(DST)입니다.
어떻게 동작하나
시뮬레이터의 이름은 VOPR(Viewstamped Operation Replicator)입니다. 영화 워게임의 슈퍼컴퓨터 WOPR에서 따왔습니다.
ticks × resolution, 곱셈 한 번이다.코어닷투데이가 2026년 8월 저장소를 세어 보니 Zig 154,770줄, 함수 4,085개, assert 호출 8,180개로 함수당 정확히 2.00개였습니다. TigerStyle(팀의 엔지니어링 규칙)의 "함수당 평균 최소 두 개"가 문서에만 있는 규칙이 아니라는 뜻입니다.
설계에도 같은 태도가 깔려 있습니다. 시작 뒤에는 메모리를 할당하지 않고(정적 할당), 블록의 체크섬은 그 블록을 가리키는 부모가 들고 있어 엉뚱한 자리의 데이터를 바로 잡아내며, 리플리카의 데이터 파일은 바이트 단위로 같아 손상된 블록 하나만 옆에서 받아 옵니다. 클러스터는 6대를 권장하는데, 커밋은 3대 확인으로 하고 프라이머리 교체 때는 4대를 모아 두 집합이 반드시 겹치게 합니다(유연한 쿼럼). 이 교집합 성질도 주석이 아니라 런타임 단언으로 박혀 있습니다.
문서에 따르면 VOPR 함대는 1,024코어에서 24시간 내내 최신 main을 퍼징하고, 실패한 씨앗은 따로 기록해 회귀 테스트가 됩니다. 브라우저에서 결함을 던져 볼 수 있는 sim.tigerbeetle.com도 있습니다.
빠른 시작
README의 단일 리플리카 클러스터입니다(리눅스 기준, 다른 플랫폼은 docs.tigerbeetle.com/start).
curl -Lo tigerbeetle.zip https://linux.tigerbeetle.com && unzip tigerbeetle.zip
./tigerbeetle format --cluster=0 --replica=0 --replica-count=1 --development 0_0.tigerbeetle
./tigerbeetle start --addresses=3000 --development 0_0.tigerbeetle
# 다른 터미널에서
./tigerbeetle repl --cluster=0 --addresses=3000
# > create_accounts id=1 code=10 ledger=700, id=2 code=10 ledger=700;
# > create_transfers id=1 debit_account_id=1 credit_account_id=2 amount=10 ledger=700 code=10;
# > lookup_accounts id=1, id=2;
시뮬레이터를 직접 돌리려면 저장소를 받아 씨앗 하나를 줍니다. 저장소가 Zig 컴파일러 버전을 직접 고정합니다.
git clone https://github.com/tigerbeetle/tigerbeetle && cd tigerbeetle
./zig/download.sh
./zig/zig build vopr -- 123 # 씨앗 123으로 클러스터 하나를 시뮬레이션
언제 쓰고, 언제 피하나
| 상황 | TigerBeetle이 맞는다 | 다른 방법을 먼저 본다 |
|---|---|---|
| 워크로드 | 쓰기 위주, 수익 계정 같은 핫 계정에 경합이 몰리는 거래 기록 | 읽기 위주, 복잡한 조인과 임의 질의 |
| 데이터 | 가치의 이동으로 모델링되는 것 — 결제·정산·포인트·크레딧·API 과금 | 사용자 프로필·상품 카탈로그처럼 자주 안 바뀌는 일반 데이터 |
| 역할 | 일반 DB 옆에 두는 원장 전용 엔진, user_data 필드로 연결 | 일반 DB를 대체하려는 시도 |
| 운영 | 리눅스 · io_uring · 6대 구성이 가능한 환경 | 서버리스·관리형만 쓰는 환경 (관리형 서비스는 별도) |
데이터베이스를 쓰지 않더라도 방법론은 가져올 수 있습니다. 코드에서 now()를 직접 부르지 않고 주입받기, 전역 난수 대신 씨앗을 받은 PRNG 쓰기, 실패한 씨앗을 회귀 테스트로 승격하기는 비용이 낮고 대부분의 DST가 여기서 시작합니다. 에이전트가 하루에 수천 줄을 만드는 지금은 "같은 우주에서 반복 검증"하는 능력과, 사람이 다 읽지 못한 코드에서 계약 위반을 잡는 단언의 값이 더 커졌습니다.
한계와 주의
- 시뮬레이션은 상태 공간을 탐색할 뿐 정의하지 않는다. 2025년 6월 Jepsen이 0.16.11을 분석해 안전성 문제 두 건을 찾았는데, 그중 하나는 VOPR의 워크로드 생성기가 지나치게 잘 짜여 두 인덱스가 늘 맞춰져 있던 탓에 지그재그 병합 조인의 한 경로를 한 번도 밟지 않아서 생겼습니다. 커버리지 지표로도 보이지 않는 사각지대였습니다.
- '하루에 2천 년'은 어림 곱셈이다. 1,024코어 × 700배 가속 × 24시간이고, 한 클러스터의 2천 년이 아니라 여러 클러스터의 짧은 생애를 합친 값입니다.
- 의도적으로 다루지 않는 결함이 있다. 오배치 쓰기는 저장소당 하나만 주입합니다. 이중 결함은 결함 모델 밖이라고 소스 주석에 적혀 있습니다.
- 함수당 단언 두 개, 의존성 최소화, 함수 70줄 제한은 대부분의 팀에 과하다. 전부 따라 하기보다 돈·재고·권한처럼 틀리면 안 되는 곳의 불변식부터 단언으로 바꾸는 편이 현실적입니다.
- 형식 검증(TLA+)은 알고리즘을, 결정론적 시뮬레이션은 구현을, Jepsen 같은 외부 검증은 내부 가정 바깥을 봅니다. 셋은 경쟁이 아니라 서로의 사각지대를 덮는 관계입니다.
