PostgreSQL에서 고가용성을 위한 동기 복제 설정
미션 크리티컬 애플리케이션에는 고가용성(HA)을 위해 PostgreSQL을 구성하는 것이 매우 중요합니다. 비동기 복제는 성능상의 이점을 제공하지만, 기본 서버에 변경 사항이 완전히 전송되기 전에 실패할 경우 데이터 손실의 위험을 내포합니다. 동기 스트리밍 복제는 트랜잭션이 기본 서버와 지정된 최소 하나 이상의 대기 서버의 WAL(Write-Ahead Log)에 성공적으로 기록된 후에만 커밋된 것으로 간주되도록 보장함으로써 이 문제를 해결합니다. 이를 통해 제로 데이터 손실 복구 목표 시간(RPO)을 보장할 수 있습니다.
이 종합 가이드는 강력하고 제로 데이터 손실 PostgreSQL 복제 설정을 구축하는 데 필요한 필수 구성 단계를 안내합니다. 이 고가용성 아키텍처의 근간이 되는 wal_level 및 synchronous_commit과 같은 중요한 매개변수에 중점을 둘 것입니다.
전제 조건
시작하기 전에 PostgreSQL 주 버전이 동일한 두 개의 PostgreSQL 서버(기본 및 대기)가 설정되어 있는지 확인하십시오. 두 서버는 네트워크 연결이 가능해야 합니다. 이 가이드에서는 다음을 가정합니다.
- 기본 호스트 이름/IP:
pg_primary - 대기 호스트 이름/IP:
pg_standby - 복제 사용자:
repl_user(적절한 권한으로 생성됨) - 데이터베이스 이름:
mydb
1단계: 기본 서버 구성
기본 서버는 스트리밍 복제를 활성화하고 동기 커밋에 필요한 WAL(Write-Ahead Log)을 관리하기 위해 특정 설정을 요구합니다.
A. 기본 서버에서 postgresql.conf 조정
기본 서버의 postgresql.conf 파일을 편집합니다. 스트리밍 복제에는 다음 매개변수가 필수적입니다:
# --- 복제에 필수 ---
listen_addresses = '*' # 대기 서버의 연결 허용
wal_level = replica # 'replica' 또는 그 이상('logical' 등)이어야 함
max_wal_senders = 10 # 대기 서버로부터의 최대 동시 연결 수
max_replication_slots = 10 # 영구 복제 스트림에 필요한 슬롯 수
# --- 동기 커밋에 필수 ---
synchronous_standby_names = '1 (standby_app_name)' # 필수 대기 서버 지정
# --- 선택 사항이지만 권장됨 ---
wal_log_hints = on # WAL 볼륨이 증가하지만 더 안전한 복제를 위해 권장됨
shared_preload_libraries = 'pg_stat_statements' # 모니터링을 사용하는 경우
주요 매개변수 설명:
wal_level = replica: 이는 대기 서버가 데이터베이스 상태를 재구성할 수 있도록 WAL에 충분한 정보가 기록되도록 보장합니다. 동기 커밋의 경우 이 수준이 최소 요구 사항입니다.synchronous_standby_names: 이는 쓰기를 승인해야 하는 대기 서버를 정의하는 핵심 설정입니다.(N (standby_name))구문을 사용하여 정의합니다.N=1이면 최소한 하나의 대기 서버가 쓰기를 확인해야 트랜잭션이 커밋됩니다.
B. 호스트 기반 인증(pg_hba.conf) 구성
기본 서버는 복제 목적으로 대기 서버(들)로부터의 복제 사용자 연결을 허용해야 합니다.
기본 서버의 pg_hba.conf에 항목을 추가합니다:
# TYPE DATABASE USER ADDRESS METHOD
host replication repl_user pg_standby/32 scram-sha-256
pg_standby/32를 실제 대기 서버의 IP 주소 또는 서브넷으로 대체하십시오.
C. 복제 슬롯 및 사용자 생성
기본 서버에서 PostgreSQL에 연결하여 필요한 사용자 및 복제 슬롯을 생성합니다.
1. 복제 사용자 생성:
CREATE ROLE repl_user WITH REPLICATION LOGIN PASSWORD 'a_strong_password';
2. 복제 슬롯 생성:
이 슬롯은 대기 서버가 수신 확인을 할 때까지 WAL 세그먼트를 보존하여 대기 서버가 일시적으로 연결 해제되더라도 데이터 손실을 방지합니다.
SELECT pg_create_physical_replication_slot('standby_app_name');
- 명명 참고 사항: 여기에 제공된 이름(
standby_app_name)은 기본 서버의synchronous_standby_names에 지정된 이름과 일치해야 합니다.
D. 기본 서버 다시 시작
기본 서버에서 PostgreSQL 서비스를 다시 시작하여 모든 구성 변경 사항을 적용합니다.
sudo systemctl restart postgresql
2단계: 대기 서버 구성
대기 서버는 복구 구성을 사용하여 기본 서버로부터 WAL 레코드를 스트리밍하도록 구성됩니다.
A. 기본 백업
스트리밍을 시작하기 전에 대기 서버는 기본 서버 데이터 디렉터리의 전체 복사본이 필요합니다. 먼저 대기 서버에서 PostgreSQL을 중지합니다.
sudo systemctl stop postgresql
pg_basebackup을 사용하여 기본 백업을 수행합니다. 경로 및 연결 세부 정보를 필요한 대로 대체하십시오:
# pg_basebackup 유틸리티를 사용하는 예
pg_basebackup -h pg_primary -D /var/lib/postgresql/15/main/ -U repl_user -P -Xs -R -W
-D: 대기 서버의 대상 데이터 디렉터리.-U: 복제 사용자.-P: 진행 상황 표시.-Xs: 기본 백업 중에 필요한 WAL 파일 포함.-R:standby.signal파일을 자동으로 생성하고postgresql.auto.conf(또는 복구 구성)에 필요한 연결 설정을 생성합니다.
B. 대기 서버에서 postgresql.conf 구성
대기 서버에서 postgresql.conf가 복제본으로 작동하도록 허용하는지 확인합니다. 여기서 주요 설정은 기본 서버에서 사용된 슬롯 이름과 일치해야 하는 애플리케이션 이름을 설정하는 것입니다.
# --- 대기 서버에서 필수 ---
primary_conninfo = 'host=pg_primary port=5432 user=repl_user password=a_strong_password application_name=standby_app_name'
hot_standby = on # 복구/대기 모드 중 읽기 쿼리 허용
C. 대기 서버 시작
대기 서버에서 PostgreSQL 서비스를 시작합니다.
sudo systemctl start postgresql
3단계: 동기 커밋 확인 및 테스트
두 서버가 모두 실행되면 연결을 확인한 다음 동기 동작을 테스트합니다.
A. 복제 상태 확인
기본 데이터베이스에 연결하고 pg_stat_replication 뷰를 확인합니다:
SELECT client_addr, application_name, state, sync_state FROM pg_stat_replication;
sync_state가 sync로 설정된 standby_app_name에 대한 항목이 표시되어야 합니다.
B. 동기 커밋 테스트
PostgreSQL이 얼마나 기다려야 하는지를 결정하는 전역 매개변수는 synchronous_commit입니다. RPO=0의 경우 동기화를 강제하는 값을 사용해야 합니다.
1. 전역 동작 설정
1단계에서 보여준 대로 기본 서버에 synchronous_standby_names를 구성한 경우, synchronous_commit이 on(기본값) 또는 remote_write로 설정되면 기본 동작은 필요한 대기 서버를 기다리도록 강제합니다.
가장 강력한 보장을 위해 postgresql.conf에서 이를 명시적으로 remote_write 또는 remote_apply(대기 서버가 디스크에 데이터를 플러시했는지 확인해야 하는 경우)로 설정하십시오.
# 기본 서버의 postgresql.conf에서
synchronous_commit = remote_write
경고:
synchronous_commit = remote_write또는on을 설정하면 비동기 모드(off또는local)에 비해 트랜잭션 지연 시간이 상당히 증가합니다. 이 지연 시간은 기본 서버와 동기 대기 서버 간의 네트워크 속도와 직접적으로 연관됩니다.
2. 트랜잭션 내에서 테스트
(전역 구성 변경 없이) 트랜잭션별로 설정하려면 세션 또는 트랜잭션별로 설정할 수 있습니다.
-- 기본 서버에 연결
BEGIN;
SET LOCAL synchronous_commit = remote_write;
INSERT INTO sales (item, amount) VALUES ('Widget A', 100);
-- 이 INSERT는 'standby_app_name'이 수신을 확인할 때까지 차단됩니다.
COMMIT;
-- COMMIT은 대기 서버가 WAL 쓰기를 승인한 후에만 성공합니다.
트랜잭션 중에 동기 대기 서버와의 연결이 끊어지면 기본 서버는 무한정 기다리거나(대기 서버가 깔끔하게 연결 해제된 경우) synchronous_commit_fallback_on_error 설정에 따라 폴백됩니다(기본값은 on으로, 이 경우 트랜잭션이 실패하거나 교착 상태에 빠질 수 있습니다).
동기 HA를 위한 모범 사례
- 전용 대기 서버 사용: 쓰기 성능에 심각한 영향을 미치므로 지연 시간이 짧은(물리적으로 가까운) 대기 서버만 동기 복제 목록에 할당하십시오.
- 복제 지연 모니터링: 동기 모드에서도 대기 서버 지연 시간을 모니터링하십시오. 기술적으로는 'sync' 상태이지만 WAL 처리에 너무 오래 걸리는 느린 대기 서버는 사용자 경험에 영향을 줄 수 있습니다.
- 연결 폴백:
synchronous_commit_fallback_on_error설정을 이해하십시오.off로 설정하면 커밋 중에 동기 대기 서버와의 통신에 실패하면 기본 서버의 트랜잭션이 실패하여 잠재적인 데이터 불일치를 방지하지만 가용성에 즉시 영향을 미칩니다. - 여러 대기 서버 사용: 동기 설정 내에서 최대 이중화를 위해
synchronous_standby_names = '2 (standby1, standby2)'를 구성하여 두 개의 독립된 대기 서버로부터의 커밋을 요구하십시오.