Innovating today, leading tomorrow

OpenSQL_Internals
[OpenSQL] PostgreSQL의 WAL(Write Ahead Log)

[OpenSQL] PostgreSQL의 WAL(Write Ahead Log)

데이터베이스 관리 시스템은 데이터 무결성(Data Integrity)를 보장해야만 합니다. 다수의 데이터베이스는 데이터 무결성을 보장하기 위해 WAL(Write Ahead Log)이라는 방식을 사용합니다.

Reference. Mohan, Chandrasekaran, et al. “ARIES: A transaction recovery method supporting fine-granularity locking and partial rollbacks using write-ahead logging.” ACM Transactions on Database Systems (TODS) 17.1 (1992): 94-162. https://www.postgresql.org/docs/current/wal-reliability.html

Data Integrity

WAL에 대해 논의하기 전, 데이터 무결성에 대하여 가볍게 알아보도록 하겠습니다. 데이터 무결성은 데이터베이스가 운영되는 동안 데이터의 정확성과 일관성을 유지하는 것을 의미합니다. 사실 데이터 무결성은 데이터베이스 뿐만 아니라 컴퓨터 과학 전반에서 광범위하게 사용되는 개념입니다. 데이터 무결성은 “사용자가 의도하지 않은 정보 변경을 방지한다”라는 목표로 달성될 수 있습니다.

데이터 무결성은 크게 물리적 무결성과 논리적 무결성으로 나누어질 수 있습니다. 이를 이해하기 위하여 무결성을 해치는 상황에 대하여 논의해보겠습니다.

물리적 무결성은 데이터 자체를 올바르게 저장하는 것과 관련되어 있습니다. 데이터베이스가 기동중인 컴퓨터의 전원이 갑자기 정전으로 인해서 꺼지거나, 네트워크 장애 등으로 데이터가 정상적으로 저장되지 않는 상황이 이에 해당한다고 할 수 있습니다.

논리적 무결성은 소프트웨어의 버그 등에서 기인한 문제이며 데이터베이스의 제약조건(Constraint), 외래키(Foreign Key)와 같은 개념이 이를 방지하기 위한 장치입니다.

본문에서 설명하는 WAL은 주로 물리적 무결성에 의해 발생하는 문제를 해결합니다.

Reference. https://en.wikipedia.org/wiki/Data_integrity

Failure in Disk

본 문단에서는 데이터베이스에서 물리적 무결성 문제가 발생하는 상황을 이해하기 위하여 데이터베이스의 정보가 실제로 디스크에 쓰여지는 과정을 간략하게 설명하겠습니다.

이를 바탕으로 데이터베이스에서 물리적 무결성 문제가 발생하는 이유를 두 가지로 요약할 수 있습니다. 첫번째는 메모리와 디스크의 속도 차이, 두번째는 영속성인 디스크와 달리 메모리와 캐시는 휘발성으로 컴퓨터가 종료되면 데이터가 사라진다는 사실 때문입니다.

디스크의 쓰기는 주로 바로 쓴다(Write-through), 나중에 쓴다(Write-back) 방식으로 이루어집니다. 어떤 방식이든 위 두 가지 이유로 인해 중간에 물리적인 문제가 발생한다면 “사용자는 디스크에 썼다고 생각하지만 실제로는 쓰여지지 않은” 무결성 문제가 발생하게 됩니다.

Reference. https://www.postgresql.org/docs/current/wal-reliability.html

Write Ahead Log (WAL)

데이터베이스의 물리적 무결성 문제를 해결하기 위해 각 벤더들은 오래 전부터 WAL이라는 기법을 도입하였습니다. WAL은 문자 그대로 **“먼저 로그를 쓴다”**라는 의미이며, 메커니즘 역시 사전적 의미에 매우 충실합니다.

PostgreSQL 공식 문서에서는 “WAL의 개념은 **데이터 파일의 변경된 내용은 해당 변경 사항이 로깅된 이후에 쓰여져야만 한다.”**라고 명기하고 있습니다. WAL을 사용하게 되면 만약 디스크에 변경된 내용을 쓰기 전, 혹은 쓰는 중에 예기치 않은 문제로 실패하였다고 하더라도 변경 사항에 대한 로그가 존재하므로 해당 명령을 다시 수행하여 이를 복구 할 수 있습니다. Oracle 또는 Tibero에서는 이 과정을 **실패한 동작을 “다시 수행한다”**라는 의미에서 REDO라고 지칭합니다.

“동작을 다시 수행한다”라는 관점은 매우 중요합니다. 이 관점을 기반으로 복구(Recovery) 뿐만 아니라 복제(Replication) 개념에도 사용될 수 있기 때문입니다. 실제 PostgreSQL은 WAL 매커니즘을 기반으로 PITR(Point-in Time Recovery)와 SR(Streaming Replication) 기능을 추가하였습니다.

Reference. https://en.wikipedia.org/wiki/Write-ahead_logging

Mohan, Chandrasekaran, et al. “ARIES: A transaction recovery method supporting fine-granularity locking and partial rollbacks using write-ahead logging.” ACM Transactions on Database Systems (TODS) 17.1 (1992): 94-162. https://www.postgresql.org/docs/current/wal-intro.html

Intermission

지금까지 데이터 무결성을 정의하고 발생하는 이유, 그리고 PostgreSQL에서 이를 해결하기 위한 방법인 WAL에 대해 설명하였습니다.

막간을 이용해 여기까지 읽고 가질 수 있는 궁금증에 대하여 논의해보겠습니다.

로그도 결국 디스크에 저장되어야 하는데 로그를 저장하는 중에 문제가 발생하면 어떻게 되는가?

→ 이러한 경우 복구할 수 없는 데이터 손상으로 간주합니다. 그럼에도 불구하고 로그만 매번 저장하는 방법으로 현 페이지 쓰기 빈도를 유지하면서 충돌 발생 시 복구가 불가능한 시점을 “상당히” 축소한 측면에서 의의가 크다고 볼 수 있습니다.

로그만 존재하면 어떻게 복구하는가? 어디까지 디스크에 썼는지도 알아야하지 않는가?

→ 체크포인트라는 개념이 실제로 해당 정보를 포함하고 있습니다. 후술하겠습니다.

WAL in PostgreSQL

Record

Reference.
https://github.com/postgres/postgres/blob/master/src/include/access/xlogrecord.h https://github.com/postgres/postgres/blob/master/src/include/access/xlog_internal.h

Write Record

이번 문단에서는 PostgreSQL이 어떤 과정을 통해 레코드를 저장하는지 설명하겠습니다.

WAL 세그먼트에 작성하는 과정은 다음과 같은 상황에서 이루어집니다.

  1. 수행중인 트랜잭션이 커밋되거나 취소되는 경우
  2. WAL 버퍼가 많은 수의 튜플로 채워진 경우
  3. WAL Writer 프로세스가 주기적으로 쓰는 경우

하단의 그림은 WAL Record가 쓰여지는 과정에 대한 모식도입니다. PostgreSQL은 WAL을 구현하기 위하여 메모리에 WAL Buffer를 디스크에 WAL Segment라는 영역을 추가하였습니다. 특정 명령어가 발생할 경우에는 WAL Buffer에 레코드를 생성하여 저장하고 위에 언급한 상황이 발생하면 디스크 영역인 WAL Segment로 저장합니다.

이제 이를 기반으로 예시를 설명하겠습니다. 하단의 예시에서는 INSERT “A” 명령과 이를 커밋하는 명령이 수행되었습니다. (1) INSERT “A” 명령을 수행하고 이에 대한 레코드를 생성하여 WAL Buffer에 저장합니다. (2) 커밋 명령을 수행하고 이에 대한 레코드를 생성하여 WAL Buffer에 저장합니다. (3) 커밋이 수행되었기 때문에 위에서 언급한 1번 상황에 해당하므로 WAL Segment에 저장합니다.

Checkpoint

직전의 Intermission에서 우리는 체크포인트라는 개념을 언급하였습니다. PostgreSQL은 일반적으로 백업을 시작하게 되면 pg_control 파일에 저장되어있는 체크포인트가 가리키는 WAL Record로부터 REDO를 수행합니다.

체크포인트는 Checkpointer라는 백그라운드 프로세스에서 관리가 수행됩니다. 체크포인트가 수행되는 조건은 다음과 같습니다.

  1. 이전 체크포인트가 끝난 시점부터 checkpoint_timeout 이상 지난 경우
  2. 전체 WAL 세그먼트 파일의 총 크기가 max_wal_size를 초과한 경우
  3. PostgreSQL가 스마트 또는 패스트 방식으로 종료된 경우
  4. CHECKPOINT 명령을 실행한 경우

체크포인트는 다음 두 가지 작업을 수행합니다.

  1. 데이터베이스 복구 준비
  2. 공유 버퍼 풀의 더티 페이지 정리. 더티 페이지는 디스크에 반영되지 않은 변경 사항이 있는(메모리 상에서) 페이지를 의미합니다

체크포인트는 다음 과정을 통해 수행됩니다.

  1. 체크포인트를 메모리 상에 저장합니다.
  2. 체크포인트 레코드를 WAL 버퍼에 저장합니다.
  3. 공유 메모리에 있는 모든 데이터를 Disk로 Flush 합니다
  4. pg_control 파일을 갱신합니다.

하단의 그림은 위의 과정의 도식화한 것입니다.

Reference.
https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_control.h
https://www.postgresql.org/docs/current/wal-internals.html

WAL 기반 기능

이번 장에서는 WAL을 기반으로 수행되는 여러 기능들에 대하여 설명하겠습니다.

Recovery

이번 문단에서는 WAL을 활용한 Recovery가 어떤 방식으로 동작하는 지 간략하게 확인해보겠습니다. 명확한 이해를 위하여 장애가 발생했을 때, WAL이 없는 상황과 WAL이 있는 상황에서 각각 어떻게 동작하는지 비교를 통해 설명하겠습니다. 다음 그림은 각 상황을 도식화한 것입니다.

수정된 데이터가 Disk에 저장된 이후에 Crash가 발생한 상황입니다. 해당 상황에서는 다행히 영구 저장공간인 Disk에 변경사항이 반영된 이후에 Crash가 발생하였기 때문에 재기동 이후 조회해도 수정된 데이터가 정상적으로 반영되어 있는 것을 확인할 수 있습니다.

불행하게도 수정된 데이터가 Disk에 저장되기 전에 Crash가 발생하였습니다. 해당 상황에서는 휘발성 공간인 메모리에만 수정 사항이 기록되어 있었습니다. 따라서, 재기동 이후에 조회하면 수정된 데이터가 반영되어 있지 않은 것을 확인할 수 있습니다.

위와 상황은 같습니다. 불행하게도 수정된 데이터가 Disk에 저장되기 전에 Crash가 발생하였습니다. 그러나 해당 시스템을 WAL을 사용하고 있기 때문에 어떤 Action을 수행하였는지에 대한 정보가 Disk 공간인 WAL Segment에 저장되어 있었습니다. 따라서, 재기동 이후에 조회해도 이를 기반으로 수정된 데이터를 정상적으로 반영한 결과를 확인할 수 있습니다.

위에서 우리는 “REDO, 다시 실행한다”라는 개념을 논의하였습니다. 이를 기반으로 WAL을 활용하여 Recovery를 수행하는 과정을 간략하게 설명하겠습니다.

Disk에 수정된 정보가 반영되기 전에 Crash가 발생하였으므로 데이터베이스에는 수정사항이 반영되지 않은 비어있는 TBL 테이블만을 가지고 있습니다. 그러나, 우리는 어디까지 저장하였는지에 대한 정보인 “Checkpoint”와 “A를 반영하고 커밋했다는 로그”, “B를 반영하고 커밋했다는 로그”를 Disk 공간인 WAL Segment에 저장하였습니다. 이를 기반으로 **TBL 테이블은 “Checkpoint 까지 반영되어 있으며, 따라서 A로 수정하고 커밋, B로 수정하고 커밋을 수행해야 복구가 완료된다.”**라는 사실을 추론할 수 있습니다. 실제로 WAL을 기반으로한 복구는 해당 과정으로 수행됩니다.

Reference.
https://github.com/postgres/postgres/blob/master/src/include/access/xlogrecovery.h
https://github.com/postgres/postgres/blob/master/src/backend/access/transam/xlogreader.c

Archiving

PostgreSQL은 WAL 세그먼트 파일을 아카이빙하는 Continuous Archiving 기능을 제공합니다. 해당 기능은 WAL 세그먼트 교체가 발생할 때, 기존의 WAL 세그먼트 파일들을 아카이브 영역으로 복사하는 기능입니다. 이때, 복사된 파일을 아카이브 로그라고 하며 해당 기능은 향후 설명할 PITR(Point-in Time Recovery)에의해 활용됩니다.

Backup

PostgreSQL은 WAL을 기반으로 백업을 수행합니다. 자세한 내용은 Backup and PITR(Point in Time Recovery) 챕터에서 설명하겠습니다.

Replication

PostgreSQL은 WAL을 기반으로 Replication을 수행합니다. 자세한 내용은 Streaming Replication 챕터에서 설명하겠습니다.

지금까지 PostgreSQL의 WAL(Write Ahead Log)에 관해 알아보았습니다

‘PostgreSQL의 WAL 2 (Base Back-up and PITR)’를 바로 이어서 확인해보세요!

광고성 정보 수신

개인정보 수집, 활용 목적 및 기간

(주)티맥스티베로의 개인정보 수집 및 이용 목적은 다음과 같습니다.
내용을 자세히 읽어보신 후 동의 여부를 결정해 주시기 바랍니다.

  • 수집 목적: 티맥스티베로 뉴스레터 발송 및 고객 관리
  • 수집 항목: 성함, 회사명, 회사 이메일, 연락처, 부서명, 직급, 산업, 담당업무, 관계사 여부, 방문 경로
  • 보유 및 이용 기간: 동의 철회 시까지

※ 위 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.
※ 필수 수집 항목에 대한 동의를 거부하는 경우 뉴스레터 구독이 제한될 수 있습니다.

개인정보의 처리 위탁 정보
  • 업체명: 스티비 주식회사
  • 위탁 업무 목적 및 범위: 광고가 포함된 뉴스레터 발송 및 수신자 관리
 

개인정보 수집 및 이용

개인정보 수집, 활용 목적 및 기간

(주)티맥스티베로의 개인정보 수집 및 이용 목적은 다음과 같습니다. 내용을 자세히 읽어보신 후 동의 여부를 결정해 주시기 바랍니다.

  • 수집 목적: 티맥스티베로 뉴스레터 발송 및 고객 관리
  • 수집 항목: 성함, 회사명, 회사 이메일, 연락처, 부서명, 직급, 산업, 담당업무, 관계사 여부, 방문 경로
  • 보유 및 이용 기간: 동의 철회 시까지

※ 위 개인정보 수집 및 이용에 대한 동의를 거부할 권리가 있습니다.
※ 필수 수집 항목에 대한 동의를 거부하는 경우 뉴스레터 구독이 제한될 수 있습니다.

개인정보의 처리 위탁 정보

  • 업체명: 스티비 주식회사
  • 위탁 업무 목적 및 범위: 광고가 포함된 뉴스레터 발송 및 수신자 관리
  •