데이터베이스로 작업할 때는 다 되게 간단해 보여. 그냥 행 추가하고, 레코드 업데이트하고, 고객 삭제하고. 근데 이 단순함 뒤에는 꽤 복잡하고 잘 짜여진 메커니즘이 숨어있어. 실제로 이 데이터들이 어디에 저장되는지 궁금하지 않아? PostgreSQL가 어떻게 서버가 갑자기 꺼져도 아무것도 안 잃는지 신기하지?
이걸 이해하려면 두 가지 핵심 포인트를 알아야 해: 데이터(테이블, 인덱스, 서비스 정보)가 실제로 어디에 저장되는지, 그리고 이 데이터를 보호하는 메커니즘 — 트랜잭션 로그, 즉 WAL(Write-Ahead Logging)이 어떻게 동작하는지.
PostgreSQL 데이터베이스 전체는 data_directory라는 특별한 디렉토리에 파일들로 저장돼. 보통 이 위치에 있어:
/var/lib/postgresql/17/main
이 폴더 안에 데이터베이스의 심장이 다 들어있어: 테이블, 인덱스, 메타정보, 설정까지. WAL 로그도 여기 있어 — 모든 변경사항을 제일 먼저 받아들이는 메커니즘이지. 데이터가 실제로 디스크의 테이블에 들어가기 전에, 먼저 WAL에 기록돼. 이건 마치 초안 같은 거야. 데이터베이스가 모든 단계를 기록해서, 만약 장애가 나도 마지막 작업까지 복구할 수 있게 해주는 거지.
이런 구조 덕분에 PostgreSQL는 진짜 불안정한 상황에서도 신뢰성과 안정성을 보장할 수 있어.
테이블
각 테이블은 실제로 별도의 파일 또는 파일 세트야. 이 파일들은 base/ 서브디렉토리에 있어. 구조는 대충 이래:
$PGDATA/base/
├── 16384/
│ ├── 12345 ← 테이블
│ ├── 12346 ← 인덱스
│ └── ...
16384— 이건 내부 데이터베이스 식별자(OID)야.12345— 이건 특정 테이블의 식별자.
테이블이 크면, PostgreSQL는 1GB씩 세그먼트로 쪼개:
12345
12345.1
12345.2
...
이 파일들은 CSV처럼 "행"이 들어있는 게 아니고 — 8KB짜리 "바이너리 페이지" 포맷이야.
WAL: Write-Ahead Logging — 그냥 "로그"가 아냐
이제 PostgreSQL에서 제일 중요하고, 자주 오해받는 부분 중 하나인 WAL, 즉 Write-Ahead Logging을 보자. 이름에 로그가 들어가 있지만, WAL은 일반적인 텍스트 로그 파일이 아니야. 에러 로그나 쿼리 로그랑은 달라. 이건 데이터 일관성과 복구를 위한 핵심 메커니즘이고, 파일 시스템의 저수준 변경을 다뤄.
WAL은 이벤트 리포트가 아니라, PostgreSQL가 데이터에 하려는 모든 변경을 미리 기록하는 거야. 이 기록은 실제로 테이블이 디스크에 수정되기 전에 일어나. 그래서 write-ahead — "먼저 기록한다"는 뜻이야.
예를 들어, 테이블에 새 행을 추가하면 PostgreSQL는:
- 바로 디스크의 테이블을 업데이트하지 않아 — 그건 느리고 위험하거든.
- 먼저 WAL에 기록해, 이 행이 추가될 거라고.
- 그리고 나서, 적당한 시점(예를 들면 백그라운드 프로세스에서) 실제로 테이블에 데이터가 들어가.
이건 마치 은행 수표랑 비슷해: 먼저 수표에 사인(WAL)하고, 그 다음에야 은행이 계좌(테이블)를 업데이트하지. 만약 뭔가 잘못되면 — 수표는 아직 있으니까, 다시 시도할 수 있어.
WAL 포맷과 구조
- WAL 파일은 바이너리 포맷으로 저장돼.
- 각 파일은 엄격하게 순서가 정해진 작업 스트림이고, 데이터 페이지, 인덱스 구조, 커밋 등 내부 변경을 설명해.
- WAL 파일 하나의 크기는 고정 — 기본값은 16MB야.
중요: WAL에는 "SQL 명령"이나 "테이블 행"이 우리가 아는 형태로 들어있지 않아. PostgreSQL 엔진이 변경을 재현할 수 있는 명령어가 페이지 단위로 들어있어.
장애가 나면 어떻게 될까?
만약 PostgreSQL 서버가 갑자기 꺼졌어 — 예를 들면 정전 때문에 — 그래도 다 끝난 건 아니야. 다음에 서버를 켜면, 데이터베이스는 당황하지 않고 디스크에서 마지막으로 저장된 "안정적인" 데이터 버전을 불러와. 그리고 나서 트랜잭션 로그(WAL)를 읽어서, 마지막 변경사항들을 차근차근 "적용"해 — 아직 메인 파일에 반영되지 않은 것들만. 그래서 결국 데이터베이스는 완전히 일관된 상태로 복구돼, 마치 아무 일도 없었던 것처럼.
WAL의 추가 기능들
Point-In-Time Recovery (PITR). WAL 파일을 저장하면, 두 번의 전체 백업 사이의 어느 시점으로든 데이터베이스를 복구할 수 있어.
스트리밍 복제. PostgreSQL는 WAL 기록을 실시간으로 다른 서버로 보낼 수 있어. 이걸로 핫 리플리카 — 메인 데이터베이스와 동기화된 복사본을 만들 수 있지.
증분 복구. 전체 백업이랑 같이 쓰면, WAL 덕분에 변경된 부분만 복구할 수 있어서, 전체 데이터베이스를 다시 복사할 필요가 없어.
바이너리 백업 만들기: pg_basebackup
pg_dump에 좀 익숙해졌다면, 이게 논리적 백업(즉, 데이터베이스 구조랑 데이터를 SQL 쿼리로 복사하는 것)에 딱 좋다는 걸 알 거야. 근데 물리적 백업이 필요하면 어떡하지? 예를 들어, 데이터베이스 파일 전체를 완전히 복제하고 싶을 때? 이럴 때 pg_basebackup이라는 툴이 있어.
pg_basebackup은 PostgreSQL 데이터를 물리적으로 복사할 수 있게 해주는 유틸리티야. 대용량 데이터베이스에서 복구 프로세스를 효율적으로 관리할 때 특히 유용하지. pg_basebackup의 가장 큰 장점은 진짜 빠르다는 거야.
pg_basebackup 기본 명령어 문법
pg_basebackup을 쓰려면, 명령어 구조부터 알아야 해. 터미널에서 이렇게 실행해:
pg_basebackup -D /backup_directory -F tar -z -P
이게 무슨 뜻인지 하나씩 보자:
-D /backup_directory— 백업 파일을 저장할 디렉토리를 지정해.-F tar— 데이터 포맷.tar옵션은.tar아카이브 파일을 만들어.plain을 쓰면 데이터베이스 파일 구조로 복사할 수도 있어.-z— 백업을 압축해서 디스크 공간을 절약해. 백업이 작아지면 항상 기분 좋지!-P— 실시간 진행 상황을 보여줘. 이거 덕분에 "서버 멈춘 거 아냐?" 걱정 안 해도 돼.
사용 예시:
pg_basebackup -D /backups/university_backup -F tar -z -P
이 명령을 실행하면 /backups/university_backup 디렉토리에 .tar 포맷의 백업이 만들어져.
pg_basebackup 사용 장점
효율성: 증분 백업 덕분에 변경되지 않은 데이터는 중복 저장하지 않아서, 시간도 공간도 아껴.
간편함: pg_basebackup 툴이 WAL 파일까지 자동으로 다 처리해줘.
신뢰성: PostgreSQL 메커니즘과 통합되어 있어서, pg_basebackup이 전체 데이터베이스의 정확한 복사본을 만들어주고, 복구도 쉽게 할 수 있어.
사용 예제
이제 실전! 아래는 PostgreSQL 데이터베이스 백업을 pg_basebackup으로 만드는 실제 예제들이야. 기본 백업, 압축 추가, 그리고 트랜잭션 로그(WAL) 아카이빙까지 — "시점 복구"도 가능하게 하는 방법을 보여줄게. 이 명령어들은 입문자도, 좀 더 고급 시나리오에도 다 쓸 수 있어.
기본 백업 만들기
pg_basebackup -D /backups/full_backup -F tar -z -P
결과: .tar 아카이브에 전체 데이터베이스 백업이 만들어져.
압축과 포맷 설정
최대 압축률로 데이터 백업을 만들어보자:
pg_basebackup -D /backups/full_backup -F tar -z -Z 9 -P
여기서 -Z 9는 압축 레벨(최대 9)을 의미해.
WAL 아카이빙
WAL 아카이빙을 설정하면, 데이터베이스를 어느 시점으로든 복구할 수 있어. WAL 백업을 위한 명령어:
pg_basebackup -D /backups/incremental_backup -F tar -z -P --wal-method=archive
GO TO FULL VERSION