본문 바로가기
C.W.K.
Stream
Lesson 09 of 10 · published

WAL 모드 — 성능의 #1 win

~14 min · wal, performance, concurrency

Level 0Scout
0 XP0/80 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

PRAGMA 한 줄, 두 자릿수 개선

SQLite의 기본 journal 모드는 DELETE야. writer가 배타 락을 잡고 reader를 막지. WAL(Write-Ahead Logging) 모드는 이 구도를 뒤집어. reader와 writer가 서로를 안 막아. reader는 앞뒤 맞는 snapshot을 보고, writer는 log 파일(db-wal) 끝에 붙이기만 하다가, 주기적으로 main DB로 checkpoint를 떠.

DB마다 한 번만 켜면 돼. 설정이 파일에 남거든.

PRAGMA journal_mode = WAL;

거의 항상 켜야 하는 이유가 셋이야.

  • reader가 writer한테 막히지 않고, 반대로도 마찬가지야.
  • write가 확 빨라져. fsync를 덜 하고 순서대로 붙이기만 하니까.
  • 동시에 뭔가 벌어지는 워크로드라면 이게 전제조건이야. 웹 서버든 async 앱이든 백그라운드로 sync하는 데스크탑 앱이든.
Warning: WAL 모드는 file locking이 제대로 도는 진짜 파일시스템을 요구해. NFS나 SMB, FUSE처럼 locking이 별나게 도는 데서는 안전하지 않아. 로컬 디스크에서만 써.

WAL은 적당한 busy_timeout과 짝을 지어. 5초에서 30초쯤이면 돼. checkpoint 도는 동안 잠깐 걸린 락에 SQLITE_BUSY로 터지는 대신 조금 기다리게 만드는 거야.

Code

'production-ready opener'·python
import sqlite3

def open_db(path: str) -> sqlite3.Connection:
    conn = sqlite3.connect(path, timeout=30.0)
    conn.execute('PRAGMA journal_mode = WAL')
    conn.execute('PRAGMA synchronous = NORMAL')   # WAL 와 안전, 더 빠름
    conn.execute('PRAGMA foreign_keys = ON')
    conn.execute('PRAGMA busy_timeout = 5000')
    return conn

# WAL 활성 확인:
print(open_db('demo.db').execute('PRAGMA journal_mode').fetchone())
# ('wal',)
수동 checkpoint — 보통은 필요 없어·sql
-- Checkpoint 강제 (실행 동안 writer 활동 일시 중단)
PRAGMA wal_checkpoint(TRUNCATE);

-- WAL 상태 확인
PRAGMA wal_checkpoint;
-- (busy, log_pages, checkpointed_pages)

External links

Exercise

WAL이 주는 이득을 네 머신에서 직접 재현해봐. 작은 벤치마크면 돼. writer thread 하나가 row를 계속 넣고, reader thread 하나가 SELECT count(*)를 계속 돌려. 기본 DELETE journal 모드로 한 번, WAL로 한 번. 양쪽 처리량을 비교하고, 병목이 어디로 옮겨갔는지 적어둬.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.