PostgreSQL Replication 서버 세팅 가이드
PostgreSQL의 Streaming Replication을 이용해 Primary-Standby 구성을 세팅하는 방법을 정리했다. 읽기 부하 분산, 장애 대비(failover), 백업 용도로 활용할 수 있다.
Replication 방식 비교
| 방식 | 단위 | 용도 |
|---|---|---|
| Streaming Replication | 전체 DB 클러스터 (물리적) | HA, failover, 읽기 분산 |
| Logical Replication | 테이블 단위 (논리적) | 선택적 복제, 버전 간 마이그레이션 |
이 글에서는 가장 일반적인 Streaming Replication을 다룬다.
환경 구성
| 역할 | 호스트 | IP |
|---|---|---|
| Primary (쓰기) | pg-primary | 10.0.0.1 |
| Standby (읽기) | pg-standby | 10.0.0.2 |
PostgreSQL 16 기준이며, 15 이상이면 동일하게 적용된다.
1. Primary 서버 설정
1-1. Replication 전용 계정 생성
-- Primary에서 실행
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'repl_password';
1-2. postgresql.conf 수정
# 외부 접속 허용
listen_addresses = '*'
# WAL 레벨 (replica 이상 필요)
wal_level = replica
# 동시 replication 연결 수
max_wal_senders = 5
# Standby가 따라잡기 위해 보관할 WAL 세그먼트
wal_keep_size = 1GB
# Replication 슬롯 수 (선택, 권장)
max_replication_slots = 5
1-3. pg_hba.conf에 Standby 접속 허용
# TYPE DATABASE USER ADDRESS METHOD
host replication replicator 10.0.0.2/32 scram-sha-256
1-4. Replication Slot 생성 (권장)
Slot을 사용하면 Standby가 꺼져 있는 동안에도 필요한 WAL이 삭제되지 않는다.
SELECT pg_create_physical_replication_slot('standby_slot');
주의: Standby가 장기간 꺼져 있으면 WAL이 무한히 쌓여 디스크가 가득 찬다. 운영 환경에서는 모니터링 필수.
1-5. Primary 재시작
sudo systemctl restart postgresql
2. Standby 서버 설정
2-1. 기존 데이터 디렉토리 비우기
# Standby에서 실행
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/16/main/*
2-2. pg_basebackup으로 Primary 복제
Primary의 전체 데이터를 Standby로 복사한다.
sudo -u postgres pg_basebackup \
-h 10.0.0.1 \
-U replicator \
-D /var/lib/postgresql/16/main \
-Fp -Xs -P -R \
-S standby_slot
옵션 설명:
| 옵션 | 설명 |
|---|---|
-Fp |
Plain 포맷 (바로 사용 가능) |
-Xs |
WAL을 스트리밍으로 전송 |
-P |
진행률 표시 |
-R |
standby.signal 파일과 연결 정보 자동 생성 |
-S |
사용할 Replication Slot 이름 |
-R 옵션이 자동으로 생성하는 파일들:
# standby.signal (빈 파일, 존재 자체가 Standby 모드를 의미)
# postgresql.auto.conf에 추가됨
primary_conninfo = 'host=10.0.0.1 user=replicator password=repl_password'
primary_slot_name = 'standby_slot'
2-3. Standby 전용 설정 (postgresql.conf)
# Standby에서 읽기 쿼리 허용
hot_standby = on
# 읽기 쿼리와 복제 충돌 시 대기 시간 (기본 30s)
max_standby_streaming_delay = 30s
2-4. Standby 시작
sudo systemctl start postgresql
3. Replication 상태 확인
Primary에서 확인:
-- 연결된 Standby 목록
SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes
FROM pg_stat_replication;
Standby에서 확인:
-- Standby 수신 상태
SELECT status, received_lsn, latest_end_lsn,
latest_end_time, sender_host
FROM pg_stat_wal_receiver;
-- 복제 지연 시간 (PostgreSQL 10+)
SELECT now() - pg_last_xact_replay_timestamp() AS replication_lag;
Slot 상태 확인:
SELECT slot_name, active, restart_lsn,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS retained_bytes
FROM pg_replication_slots;
4. Synchronous Replication (선택)
기본 Streaming Replication은 비동기(async)다. Primary가 커밋 후 Standby에 전파하므로, Primary 장애 시 최근 트랜잭션이 유실될 수 있다.
데이터 유실이 허용되지 않는 경우 동기 모드를 사용한다.
Primary의 postgresql.conf:
# Standby의 application_name과 매칭
synchronous_standby_names = 'FIRST 1 (standby1)'
# 동기 커밋 레벨
synchronous_commit = on
Standby의 primary_conninfo에 application_name 추가:
primary_conninfo = 'host=10.0.0.1 user=replicator password=repl_password application_name=standby1'
동기 모드 레벨:
| synchronous_commit | 보장 범위 | 성능 |
|---|---|---|
on |
Standby 디스크 flush 완료 | 가장 느림 |
remote_write |
Standby OS에 전달 완료 | 중간 |
remote_apply |
Standby에서 읽기 가능 | 가장 느림 + 읽기 일관성 |
주의: 동기 모드에서 Standby가 죽으면 Primary의 모든 쓰기가 멈춘다. Standby를 2대 이상 두거나 FIRST 1 (standby1, standby2)처럼 설정해야 안전하다.
5. Failover (수동 승격)
Primary에 장애가 발생하면 Standby를 Primary로 승격한다.
# Standby에서 실행
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main
# 또는 SQL로
SELECT pg_promote();
승격 후 standby.signal 파일이 자동 삭제되고, 쓰기가 가능해진다.
승격 후 해야 할 일:
# 1. 애플리케이션의 DB 연결을 새 Primary(10.0.0.2)로 변경
# 2. 기존 Primary 복구 후 Standby로 전환
# (pg_basebackup으로 새 Primary에서 다시 복제)
# 3. 기존 Replication Slot 정리 (새 Primary에서)
SELECT pg_drop_replication_slot('standby_slot');
6. 자동 Failover (Patroni)
수동 failover는 운영에서 한계가 있다. 자동 failover가 필요하면 Patroni를 사용한다.
# 아키텍처
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Patroni │ │ Patroni │ │ etcd │
│ + PG │────▶│ + PG │────▶│ cluster │
│ Primary │ │ Standby │ │ (DCS) │
└─────────┘ └─────────┘ └─────────┘
│ │
└───────┬───────┘
▼
┌───────────┐
│ HAProxy / │
│ PgBouncer │
└───────────┘
Patroni 최소 설정 (patroni.yml):
scope: pg-cluster
name: pg-node1
etcd3:
hosts: 10.0.0.10:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576 # 1MB
postgresql:
use_pg_rewind: true
parameters:
wal_level: replica
max_wal_senders: 5
max_replication_slots: 5
postgresql:
listen: 0.0.0.0:5432
connect_address: 10.0.0.1:5432
data_dir: /var/lib/postgresql/16/main
authentication:
superuser:
username: postgres
password: postgres_pass
replication:
username: replicator
password: repl_password
Patroni가 리더 선출, 자동 failover, pg_rewind를 통한 기존 Primary 재합류를 모두 처리한다.
7. Logical Replication (테이블 단위)
특정 테이블만 복제하거나, 다른 버전의 PostgreSQL 간 복제가 필요할 때 사용한다.
Primary (Publisher):
# postgresql.conf
wal_level = logical
-- Publication 생성
CREATE PUBLICATION my_pub FOR TABLE users, orders;
-- 또는 전체 테이블
CREATE PUBLICATION my_pub FOR ALL TABLES;
Standby (Subscriber):
-- 테이블 스키마는 미리 생성되어 있어야 함
-- Subscription 생성
CREATE SUBSCRIPTION my_sub
CONNECTION 'host=10.0.0.1 dbname=myapp user=replicator password=repl_password'
PUBLICATION my_pub;
Streaming vs Logical 비교:
| 항목 | Streaming | Logical |
|---|---|---|
| 복제 단위 | 전체 클러스터 | 테이블 선택 가능 |
| Standby 쓰기 | 불가 (읽기 전용) | 가능 |
| PG 버전 호환 | 동일 메이저 버전 | 다른 버전 가능 |
| DDL 복제 | 자동 | 수동 (스키마 변경 별도) |
| Failover | promote 가능 | promote 불가 |
| 성능 오버헤드 | 낮음 | 상대적으로 높음 |
8. 운영 모니터링 쿼리 모음
-- 1. 복제 지연 (Primary에서)
SELECT client_addr,
state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) AS lag_pretty
FROM pg_stat_replication;
-- 2. 복제 지연 시간 (Standby에서)
SELECT CASE
WHEN pg_last_wal_replay_lsn() = pg_last_wal_receive_lsn() THEN 0
ELSE EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp())
END AS lag_seconds;
-- 3. Slot의 WAL 보관량 (디스크 사용량 감시)
SELECT slot_name, active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots;
-- 4. 현재 서버가 Primary인지 Standby인지 확인
SELECT pg_is_in_recovery(); -- true = Standby, false = Primary
정리: 단계별 체크리스트
| 단계 | 서버 | 작업 |
|---|---|---|
| 1 | Primary | replication 계정 생성 |
| 2 | Primary | postgresql.conf 수정 (wal_level, max_wal_senders) |
| 3 | Primary | pg_hba.conf에 Standby 허용 |
| 4 | Primary | Replication slot 생성, 재시작 |
| 5 | Standby | pg_basebackup -R 실행 |
| 6 | Standby | hot_standby = on, 시작 |
| 7 | 양쪽 | pg_stat_replication / pg_stat_wal_receiver 확인 |
HA가 필요하면 Streaming Replication + Patroni 조합이 가장 검증된 구성이다. 테이블 단위 선택적 복제나 버전 간 마이그레이션이 필요한 경우에만 Logical Replication을 사용한다.
'Database > PostgreSQL' 카테고리의 다른 글
| PostgreSQL Performance Tuning 가이드 (0) | 2026.02.24 |
|---|---|
| PostgreSQL 계정 및 권한 관리 가이드 (0) | 2026.02.24 |
| PostgreSQL 데이터 백업 및 복구 (0) | 2024.10.08 |
| PostgreSQL 계정 관리 방법 (0) | 2024.10.06 |