1.4 Quickstart
이 장에서는 이 노트의 실습 구성 pg-auto-failover-lab을 사용해 monitor 하나와 PostgreSQL 노드 두 대를 실행합니다. 이어서 pg_autoctl show state로 상태를 확인하고 switchover를 한 번 실행합니다. 공식 저장소에도 citusdata/pg_auto_failover:demo 이미지를 사용하는 docker-compose.yml이 있습니다. 여기서는 PGDG 패키지 버전을 명확히 하기 위해 공식 postgres:17 이미지에 패키지를 직접 설치했습니다.
구성
실습 파일은 /examples/pg-auto-failover-lab/에 있습니다. Dockerfile은 다음 두 패키지를 설치합니다.
ARG PG_MAJOR=17
FROM postgres:${PG_MAJOR}
ARG PG_MAJOR
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
postgresql-${PG_MAJOR}-auto-failover \
pg-auto-failover-cli \
iproute2 procps \
&& rm -rf /var/lib/apt/lists/*
USER postgres
pg_autoctl이 내부에서 호출하는 initdb, pg_ctl, postgres는 root 실행을 허용하지 않습니다. 따라서 이미지 마지막에 USER postgres를 둡니다.
기동
docker compose build
docker compose up -d monitor app
docker compose up -d node1
./scripts/wait-state.sh node1 single 120
docker compose up -d node2
./scripts/wait-state.sh node2 secondary 300
모든 노드 서비스의 명령은 pg_autoctl create ... --run 한 줄로 구성됩니다. 생성이 끝나면 같은 프로세스가 keeper로 계속 실행됩니다.
node1:
command: >
pg_autoctl create postgres
--name node1 --hostname node1 --pgport 5432
--dbname appdb
--ssl-self-signed --auth trust --pg-hba-lan
--run
실습 환경에서 측정한 소요 시간은 다음과 같습니다.
| 단계 | 측정값 |
|---|---|
monitor up부터 pgautofailover.formation 조회 가능까지 | 1.7초 |
node1 up부터 single 도달까지 | 2.0초 |
node2 up부터 secondary 도달까지 | 97.8초 |
같은 단계, node1에서 CHECKPOINT를 먼저 실행한 경우 | 3.5초 |
node2에 97초가 걸린 이유는 로그에서 확인할 수 있습니다. pg_basebackup이 checkpoint를 기다리는 데 95초가 걸렸습니다.
05:24:45 9 INFO pg_basebackup: initiating base backup, waiting for checkpoint to complete
05:26:20 9 INFO pg_basebackup: checkpoint completed
pg_autoctl은 pg_basebackup에 --checkpoint=fast를 지정하지 않습니다. 따라서 PostgreSQL 기본값인 spread checkpoint를 사용합니다. 방금 initdb와 CREATE DATABASE를 마친 primary에는 dirty buffer가 남아 있습니다. spread checkpoint는 이를 checkpoint_completion_target에 맞춰 천천히 씁니다. primary에서 CHECKPOINT를 먼저 실행하면 basebackup 시작 시 쓸 buffer가 거의 없어 곧바로 끝납니다.
데이터가 큰 운영 환경에서 standby를 추가하거나 재구축할 때도 같은 대기가 발생합니다. 대기 시간은 dirty buffer 양과 checkpoint 설정에 따라 달라집니다. 수동 CHECKPOINT는 대기를 줄이지만 dirty buffer를 한꺼번에 flush합니다. 또한 직후 full-page write로 WAL이 늘어납니다. spread checkpoint는 이 I/O 부하를 줄이기 위한 기본값입니다. 따라서 운영 primary에서는 I/O 여유가 있는 시점을 선택해 실행합니다.
상태 확인
./scripts/state.sh
Name | Node | Host:Port | TLI: LSN | Connection | Reported State | Assigned State
------+-------+------------+----------------+--------------+---------------------+--------------------
node1 | 1 | node1:5432 | 1: 0/30000F8 | read-write | primary | primary
node2 | 2 | node2:5432 | 1: 0/30000F8 | read-only | secondary | secondary
Reported State는 keeper가 보고한 현재 상태입니다. Assigned State는 monitor가 정한 목표 상태입니다. 둘이 같으면 해당 노드는 안정 상태입니다. 복제 설정과 애플리케이션용 연결 문자열도 monitor에서 바로 확인할 수 있습니다.
docker compose exec monitor pg_autoctl show settings
docker compose exec monitor pg_autoctl show uri
Context | Name | Setting | Value
----------+---------+---------------------------+-----------------------------------
formation | default | number_sync_standbys | 0
primary | node1 | synchronous_standby_names | 'ANY 1 (pgautofailover_standby_2)'
node | node1 | candidate priority | 50
node | node2 | candidate priority | 50
node | node1 | replication quorum | true
node | node2 | replication quorum | true
Type | Name | Connection String
-------------+---------+-------------------------------
monitor | monitor | postgres://autoctl_node@monitor:5432/pg_auto_failover?sslmode=require
formation | default | postgres://node1:5432,node2:5432/appdb?target_session_attrs=read-write&sslmode=require
첫 switchover
scripts/writer.sh를 실행해 0.2초마다 INSERT를 수행하면서 switchover를 실행합니다.
docker compose exec -T app bash /lab/scripts/writer.sh 30 > writer.log &
docker compose exec monitor pg_autoctl perform switchover
Time | Name | Node | Host:Port | Current State | Assigned State
---------+-------+-------+------------+---------------------+--------------------
05:27:10 | node1 | 1 | node1:5432 | primary | draining
05:27:10 | node2 | 2 | node2:5432 | secondary | prepare_promotion
05:27:10 | node2 | 2 | node2:5432 | prepare_promotion | stop_replication
05:27:10 | node1 | 1 | node1:5432 | primary | demote_timeout
05:27:11 | node2 | 2 | node2:5432 | stop_replication | wait_primary
05:27:11 | node1 | 1 | node1:5432 | demote_timeout | demoted
05:27:12 | node1 | 1 | node1:5432 | demoted | catchingup
05:27:15 | node1 | 1 | node1:5432 | catchingup | secondary
05:27:15 | node2 | 2 | node2:5432 | wait_primary | primary
위 출력에서는 일부 줄을 생략했습니다. 명령은 5.5초 뒤에 반환되었습니다. 쓰기 작업에서는 INSERT 5건이 실패했습니다. 성공한 INSERT 사이의 최장 간격은 1.35초였습니다. 새 primary는 wait_primary에 도달한 순간부터 쓰기를 받습니다. primary로 바뀌는 시점은 node1이 standby로 따라잡은 뒤입니다. 이때 동기 복제가 다시 활성화됩니다.
v2.2-4.pgdg13+1의 perform switchover는 알림을 기다리는 동안 invalid input syntax for type integer 같은 ERROR 줄을 몇 개 출력합니다. 알림 대기 부분의 get_nodes() 호출에 group 인자를 잘못 전달하는 문제로 보입니다. 이 실습의 switchover 결과에는 영향이 없었습니다.
정리
docker compose --profile three down -v
-v를 붙이면 monitor와 노드의 볼륨도 삭제합니다. 다음 Part부터는 이 구성을 사용해 상태 전이, 장애, 운영 명령을 하나씩 확인합니다. 이 실습에서 확인한 주의 사항은 9.4에 정리했습니다. 해당 내용은 monitor의 PGDATABASE, /tmp의 pid 파일, IP로 기록되는 HBA 규칙입니다.