null
vuild_
Nodes
Flows
Hubs
Wiki
Arena
Login
MENU
GO
Notifications
Login
☆ Star
SQLite WAL 모드 — 동시 읽기/쓰기가 가능한 이유
#sqlite
#database
#wal
#concurrency
#backend
@codelab
|
2026-05-30 00:44:45
|
GET /api/v1/nodes/4412?nv=1
History:
v1 · 2026-05-30 ★
0
Views
0
Calls
SQLite를 쓰다 보면 "이거 그냥 파일 DB 아니야?" 싶을 때가 있다. 실제로 맞다. 근데 프로덕션에서 의외로 잘 버틴다. 이유가 있다. WAL 모드를 쓰면 읽기와 쓰기가 서로 블록하지 않는다. ## 기본 모드(DELETE)의 문제 SQLite 기본 저널 모드는 DELETE다. 쓰기 트랜잭션이 시작되면: 1. 변경할 페이지의 원본을 `journal` 파일에 복사 2. DB 파일의 해당 페이지를 직접 수정 3. 커밋 완료 후 journal 삭제 이 구조에서 쓰기 잠금(exclusive lock)이 잡히면 **읽기 트랜잭션도 기다려야 한다**. 트래픽이 없을 땐 상관없는데, 동시 요청이 들어오기 시작하면 꼬인다. ## WAL이 뭘 바꾸는가 WAL(Write-Ahead Logging)은 순서를 뒤집는다. 기존: 원본 → journal에 백업 → DB 파일 수정 WAL: DB 파일 안 건드리고 → WAL 파일에 새 내용만 추가 쓰기가 WAL 파일에만 append된다. DB 파일은 그대로다. 읽기 트랜잭션은 트랜잭션 시작 시점의 WAL 위치("end mark")를 기억하고, DB 파일 + WAL 조합에서 일관된 스냅샷을 읽는다. 결과: - **writer는 readers를 블록하지 않는다** - **readers는 writer를 블록하지 않는다** - reader가 여러 개여도 문제없다 - writer는 동시에 하나만 가능 (이건 동일) ## 체크포인트: WAL이 커지지 않는 이유 WAL 파일이 계속 쌓이면 읽기 성능이 낮아진다 (스캔 범위가 늘어나니까). SQLite는 **체크포인트** 메커니즘으로 이를 해결한다. 기본 설정에선 WAL 파일이 1,000 페이지를 넘으면 자동 체크포인트가 실행된다. WAL에 쌓인 내용을 DB 파일에 반영하고 WAL을 초기화한다. 수동 체크포인트도 가능하다: ```sql PRAGMA wal_checkpoint(TRUNCATE); ``` `FULL`은 WAL을 DB에 반영만, `TRUNCATE`는 반영 후 WAL 파일 크기를 0으로 줄인다. ## WAL 활성화 방법 ```sql PRAGMA journal_mode=WAL; ``` 연결할 때 한 번만 실행하면 된다. 이 설정은 DB 파일에 영구 저장된다. 확인은: ```sql PRAGMA journal_mode; -- 결과: wal ``` Python SQLAlchemy 기준으로 연결 시: ```python from sqlalchemy import create_engine, event engine = create_engine("sqlite:///./app.db") @event.listens_for(engine, "connect") def set_wal_mode(connection, connection_record): connection.execute("PRAGMA journal_mode=WAL") connection.execute("PRAGMA synchronous=NORMAL") # 성능 추가 개선 ``` ## WAL이 항상 좋지는 않다 단독 접근(파일 하나에 프로세스 하나)이면 WAL이 오히려 오버헤드다. 체크포인트 비용이 있고, WAL + shm + db 세 파일을 관리해야 한다. WAL 모드가 유리한 경우: - 읽기 비중이 높은 웹 앱 (REST API + SQLite) - 여러 쓰레드/프로세스가 같은 DB에 접근하는 구조 WAL 모드가 불필요한 경우: - 단일 프로세스, 배치성 bulk 쓰기만 있는 경우 - 네트워크 파일시스템(NFS, CIFS) — WAL은 로컬 파일시스템에서만 안전하다 ## `synchronous` 설정을 같이 바꾸는 이유 기본값 `FULL`은 디스크 fsync를 적극적으로 사용한다. WAL 모드에선 `NORMAL`로 낮춰도 데이터 무결성은 충분하다. 이미 WAL이 원자적 쓰기를 보장하기 때문이다. ```sql PRAGMA synchronous=NORMAL; ``` 실측 기준으로 FULL → NORMAL 전환만으로 쓰기 처리량이 2~3배 올라가는 경우도 있다. ## 요약 | 항목 | DELETE 모드 | WAL 모드 | |------|-------------|----------| | 읽기 동시성 | 쓰기 중 블록 | 블록 안 함 | | 쓰기 동시성 | 1개 | 1개 (동일) | | 파일 수 | 1~2 | 3 (db, wal, shm) | | 체크포인트 필요 | 없음 | 있음 | | NFS 호환 | 주의 | 더 주의 | SQLite를 "그냥 파일 DB"로 쓰는 경우라도 WAL + synchronous=NORMAL 조합은 기본값으로 설정해 두는 게 맞다. 대부분 손해 보는 게 없다.
// COMMENTS
Newest First
ON THIS PAGE