WAL (Write-Ahead Logging)
WAL (Write-Ahead Logging)
Write-Ahead Logging(WAL)은 데이터 무결성을 보장하기 위한 표준적인 방법이에요. 자세한 설명은 거의 모든 트랜잭션 처리 관련 서적에서 찾을 수 있을 만큼 널리 쓰이는 기법인데요, 핵심 개념 자체는 아주 단순합니다.
WAL의 중심 개념을 한 문장으로 정리하면 이렇습니다. 데이터 파일(테이블과 인덱스가 저장되는 곳)의 변경은 반드시 그 변경이 로그에 기록된 뒤에만 수행되어야 한다는 거예요. 좀 더 정확히 말하면, 변경 내용을 담은 WAL 레코드가 영구 저장소에 플러시된 이후에만 데이터 파일을 실제로 수정할 수 있습니다.
이 절차를 따르면, 트랜잭션이 커밋될 때마다 데이터 페이지를 매번 디스크로 플러시할 필요가 없어져요. 왜냐하면 크래시가 발생해도 로그를 이용해 데이터베이스를 복구할 수 있다는 걸 알고 있기 때문입니다. 데이터 페이지에 아직 적용되지 않은 변경이 있다면, 그 변경들을 WAL 레코드로부터 다시 실행(redo)하면 돼요. 이걸 롤포워드 복구(roll-forward recovery)라고 하며, 흔히 REDO라고도 부릅니다.
WAL을 쓰면 정말 좋은 점
먼저, WAL은 크래시 이후 데이터베이스 파일의 내용을 복원해 주기 때문에, 데이터 파일이나 WAL 파일을 안정적으로 저장하기 위해 저널링 파일 시스템이 꼭 필요한 건 아니에요. 오히려 저널링은 성능을 떨어뜨릴 수 있는데요, 특히 저널링이 파일 시스템 데이터를 디스크로 플러시하게 만들 때 그렇습니다. 다행히도 저널링 중 데이터 플러시는 파일 시스템 마운트 옵션으로 끄는 경우가 많습니다. 예를 들어 리눅스 ext3 파일 시스템의 data=writeback 같은 옵션이 그런 역할을 해요. 다만 저널링 파일 시스템은 크래시 이후 부팅 속도를 높여 주기는 합니다.
다음으로, WAL을 사용하면 디스크 쓰기 횟수가 크게 줄어듭니다. 트랜잭션이 커밋됐음을 보장하려면 WAL 파일만 디스크에 플러시하면 되고, 트랜잭션이 바꾼 모든 데이터 파일을 플러시할 필요가 없기 때문이에요. 그리고 WAL 파일은 순차적으로 기록되므로, WAL을 동기화하는 비용이 데이터 페이지를 플러시하는 비용보다 훨씬 작습니다. 이 장점은 데이터 저장소의 서로 다른 부분을 건드리는 작은 트랜잭션을 많이 처리하는 서버에서 특히 두드러지죠. 게다가 서버가 작은 동시 트랜잭션을 여럿 처리할 때는, WAL 파일을 fsync 한 번 하는 것만으로도 여러 트랜잭션을 한꺼번에 커밋할 수 있어요.
마지막으로, WAL 덕분에 온라인 백업과 특정 시점 복구(point-in-time recovery)도 가능해집니다. WAL 데이터를 아카이빙해 두면, 사용 가능한 WAL 데이터가 커버하는 임의의 시점으로 되돌릴 수 있어요. 방법은 이렇게 간단합니다. 데이터베이스의 과거 물리 백업을 설치한 다음, 원하는 시점까지만 WAL을 재생(replay)하면 됩니다. 여기서 재미있는 점은, 물리 백업이 데이터베이스 상태의 순간 스냅샷일 필요가 없다는 거예요. 백업이 일정 기간에 걸쳐 만들어졌다면, 그 기간 동안의 WAL을 재생함으로써 내부의 불일치를 바로잡을 수 있습니다.