본문으로 건너뛰기

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 규칙입니다.