GN⁺: SQLite: Wal2 모드
(sqlite.org)Wal2 모드 활성화/비활성화
- SQLite의 "Wal2" 모드는 "wal (Write-Ahead Logging)" 모드와 매우 유사함.
- 데이터베이스를 wal2 모드로 변경하려면
PRAGMA journal_mode = wal2;
명령 사용. - "wal" 모드에서 직접 "wal2" 모드로 변경 불가능하며, 먼저 롤백 모드로 변경해야 함.
- wal 모드 데이터베이스를 wal2 모드로 변경하기 위해
PRAGMA journal_mode = delete;
후PRAGMA journal_mode = wal2;
명령을 사용. - wal2 모드 데이터베이스는 해당 브랜치에서 컴파일된 SQLite 버전에서만 접근 가능.
- 다른 버전의 SQLite를 사용하려고 하면 SQLITE_NOTADB 오류 발생.
- wal2 모드 데이터베이스를 롤백 모드로 변경하여 모든 버전의 SQLite에서 접근 가능하게 하려면
PRAGMA journal_mode = delete;
명령 사용.
Wal2 모드의 장점
- 기존 wal 모드에서는 작성자가 데이터베이스에 데이터를 쓸 때 데이터베이스 파일을 직접 수정하지 않고 "-wal" 파일에 새 데이터를 추가함.
- 읽기 작업은 원본 데이터베이스 파일과 "-wal" 파일 모두에서 데이터를 읽음.
- 어느 시점에 "-wal" 파일에서 데이터베이스 파일로 데이터가 복사되며, 이를 "체크포인트"라고 함.
- 체크포인트는
PRAGMA wal_checkpoint
또는sqlite3_wal_checkpoint_v2()
를 통해 명시적으로 수행되거나,PRAGMA wal_autocheckpoint
를 설정하여 자동으로 수행됨(기본 설정). - 체크포인터는 작성자를 차단하지 않고, 작성자도 체크포인터를 차단하지 않음.
- 하지만 체크포인트 중에 작성자가 데이터베이스에 쓰면 새 데이터가 wal 파일 끝에 추가되어 wal 파일이 계속 커질 수 있음.
- wal2 모드에서는 체크포인터가 방해받지 않고 완료할 기회가 없어도 wal 파일이 무한정 커지는 문제가 없음.
- wal2 모드에서는 하나 대신 두 개의 wal 파일("-wal" 및 "-wal2")을 사용함.
- 데이터가 쓰여질 때, 작성자는 첫 번째 wal 파일에 새 데이터를 추가하기 시작함.
- 첫 번째 wal 파일이 충분히 커지면, 작성자는 두 번째 wal 파일에 데이터를 추가하기 시작함.
- 이후 첫 번째 wal 파일은 체크포인트가 가능하며, 두 번째 wal 파일이 충분히 커지고 첫 번째 파일이 체크포인트되면 다시 첫 번째 파일로 전환함.
응용 프로그래밍
- 사용자 관점에서 wal과 wal2 모드의 주요 차이점은 체크포인트와 관련이 있음.
- wal 모드에서는 언제든지 체크포인트를 시도할 수 있지만, wal2 모드에서는 작성자가 "다른" wal 파일로 전환한 후에야 체크포인트가 가능함.
- wal 모드에서는 트랜잭션이 커밋된 후 wal 파일의 총 페이지 수를 인자로 사용하여 wal-hook(콜백)이 호출됨.
- wal2 모드에서는 wal-hook이 두 wal 파일의 총 미체크포인트 페이지 수를 인자로 사용하거나, "다른" wal 파일이 비어 있거나 이미 체크포인트된 경우 0을 인자로 사용하여 호출됨.
- 클라이언트는 wal2 모드 데이터베이스에 대해 wal 모드와 동일한 체크포인트 전략을 사용하는 것이 권장됨.
- wal-hook은 트랜잭션이 디스크에 커밋되고 데이터베이스 잠금이 해제된 후에 호출되지만,
sqlite3_step()
호출 내부에서 발생함. - BEGIN CONCURRENT 시스템에서는 wal-hook 내에서 체크포인트를 실행하는 대신, 애플리케이션 뮤텍스가 해제된 후에 이 작업을 연기하는 스레드를 사용할 수 있음.
GN⁺의 의견
- SQLite의 wal2 모드는 데이터베이스의 동시성과 효율성을 향상시키는 새로운 저널링 방식을 제공함.
- wal 파일의 무한 증가 문제를 해결하여 시스템의 안정성과 성능을 개선하는 것이 중요함.
- 개발자들은 wal2 모드의 도입으로 인해 데이터베이스 체크포인트 전략을 재고하고, 더 나은 동시성을 위해 적절한 체크포인트 로직을 구현해야 할 필요가 있음.
Hacker News 의견
-
WAL2 모드에서는 하나 대신 두 개의 WAL 파일을 사용함. 파일은 "<데이터베이스>-wal"과 "<데이터베이스>-wal2"로 명명됨. 데이터가 데이터베이스에 쓰여질 때, 쓰기 작업은 첫 번째 WAL 파일에 새 데이터를 추가하는 것으로 시작함. 첫 번째 WAL 파일이 충분히 커지면, 쓰기 작업은 두 번째 WAL 파일에 데이터를 추가하도록 전환함. 이 시점에서 첫 번째 WAL 파일은 체크포인트를 할 수 있고(이후에 덮어쓸 수 있음), 두 번째 WAL 파일이 충분히 커지고 첫 번째 파일이 체크포인트된 후에는 다시 첫 번째 WAL 파일로 전환함. 이런 과정이 계속됨.
- 이 방식은 매우 논리적이어서 처음부터 WAL 모드가 이렇게 구현되지 않은 이유를 이해할 수 없음. 아마도 시기상조로 여겨진 최적화였을 수도 있음.
- 이 모드가 일반적으로 사용 가능해지기를 기대함.
-
Bedrock
- Bedrock은 더 흥미로운 브랜치임.
- WAL2 + CONCURRENT 기능을 포함함.
- Expensify가 단일 노드에서 4M QPS까지 확장하는 데 사용하는 브랜치임(6년 전).
-
WAL2 모드와 유사한 기술인 left-right primitive에 대한 링크 제공.
- 이 기술은 링크된 구현보다 오래되었지만 독립적으로 재발견되었으며, 특히 Noria라는 다른 고성능 SQL 데이터베이스를 지원하기 위해 작성됨.
-
WAL2 모드에서는 하나 대신 두 개의 WAL 파일을 사용함. 파일은 "<데이터베이스>-wal"과 "<데이터베이스>-wal2"로 명명됨.
- 얼마나 많은 사람들이 wal 파일을 삭제할지 궁금함. wal2로 전환했으니 wal 파일은 남은 것으로 생각할 수 있기 때문.
-
Microsoft SQL Server는 유사한 아키텍처를 사용하지만 별도의 로그 파일 대신 물리적(디스크 상의) 로그 파일 내에 Virtual Log Files(VLF)를 할당함. VLF는 링 버퍼에서 할당되며 수천 개까지 있을 수 있음.
-
이 기능이 아직 출시되지 않았다는 것을 알 수 있음.
-
WAL이 데이터 무결성을 유지하고 충돌로부터 복구하는 데 도움이 되기 위해 존재한다는 점이 항상 걱정되었음. 그러나 파일 자체가 배치로 쓰여지고(디스크에 신뢰성 있게 커밋됨) 데이터베이스의 모든 변경 후가 아니라 성능을 얻기 위해 그렇게 함. 이것이 목적을 무너뜨리지 않는가? 일반적으로 데이터베이스에 특정하지 않고, 이에 대한 답을 찾지 못함.
-
이것이 Litestream과 같은 새로운 분산 SQLite 시스템에 어떤 영향을 미칠지 궁금함.
-
그래서 기본적으로 데이터베이스를 위한 더블 버퍼링인가? 이해가 됨.
-
WAL2 모드는 HC-tree 백엔드 연구의 벤치마크에 포함되었음.