본문으로 건너뛰기

5.3 replica 생성

DCS에 initialize 키가 있는 상태에서 빈 데이터 디렉토리로 시작한 노드는 bootstrap 대신 replica 생성 절차를 밟는다(5.1의 분기). 어떤 방법으로 데이터를 복사할지는 postgresql.create_replica_methods가 정하고, 목록이 비어 있으면 pg_basebackup을 쓰는 basebackup이 기본이다.

create_replica_methods 계약

create_replica_methods는 시도할 방법의 ordered list다. Patroni는 목록을 위에서부터 순서대로 실행하고, exit code 0을 반환하는 첫 번째 방법에서 멈춘다. 전부 실패하면 다음 HA loop cycle에 처음부터 다시 시도한다.

postgresql:
  create_replica_methods:
    - pgbackrest
    - basebackup
    flowchart TD
  NEED["replica 생성 필요"] --> M1["method 1 실행"]
  M1 -->|exit 0| OK["replica 구성, 시작"]
  M1 -->|실패| M2["method 2 실행"]
  M2 -->|exit 0| OK
  M2 -->|실패| REST["나머지 순서대로"]
  REST -->|전부 실패| RETRY["다음 loop cycle에<br/>처음부터 재시도"]
  RETRY --> M1
  

bootstrap method가 체이닝 없이 단판 승부인 것과 달리, replica 생성은 목록 순서대로 fallback이 이어진다는 점이 두 계약의 가장 큰 차이다.

Patroni가 스크립트에 전달하는 것

각 method는 같은 이름의 설정 섹션이 필요하고, 최소한 command를 가진다. Patroni는 command에 네 가지 인자를 --name=value 형식으로 전달한다.

인자
--scope클러스터 이름
--datadirreplica data directory 경로
--role항상 replica
--connstring복제 소스 멤버(primary 또는 다른 replica) 접속 문자열

--connstring에 담긴 계정은 SQL 명령과 replication protocol 명령을 모두 실행할 수 있다. 설정 섹션에 적은 사용자 정의 key: value도 같은 --name=value 형식으로 뒤에 붙는다.

동작을 바꾸는 특수 파라미터가 세 개 있다.

  • no_leader: 정의하면 leader가 없어도 method를 호출한다. 이때 --connstring은 빈 문자열이다. 백업 저장소처럼 클러스터 밖의 소스에서 복원하는 method를 위한 옵션이다.
  • keep_data: True: method 호출 전에 PGDATA를 지우지 않는다. 기존 파일을 재활용하는 delta restore류 도구와 짝을 이룬다.
  • no_params: True: 위 파라미터 전달을 생략한다.

기본 method basebackup

별도 설정 없이도 동작한다. 복사 소스는 leader다. 단 clonefrom tag가 true인 replica가 하나라도 있으면 leader 대신 그쪽에서 pg_basebackup을 뜨고, 여럿이면 랜덤으로 하나를 고른다. leader의 복사 부하를 replica로 돌리고 싶은 배치에서 쓰는 tag다.

pg_basebackup에 옵션을 넘기려면 postgresql.basebackup 섹션을 쓴다. map과 list 두 형식을 지원하며, 값이 없는 플래그 옵션은 list 형식으로 섞는다.

# map 형식
postgresql:
  basebackup:
    max-rate: '100M'
    checkpoint: 'fast'
# list 형식 (값 없는 옵션 혼용)
postgresql:
  basebackup:
    - verbose
    - max-rate: '100M'
    - waldir: /pg-wal-mount/external-waldir
옵션은 long 형식만 허용되고, Patroni는 옵션 이름과 값을 검증하지 않는다. 접속 문자열을 바꾸는 옵션이나 tar 출력, 압축 같은 출력 형식 옵션을 주면 replica를 만들지 못한다. WAL 디렉토리를 symlink로 분리한 구성이라면 --waldir를 직접 지정해야 한다(PostgreSQL 10 이상).

replicatefrom tag와 cascading replication

tags.replicatefrom에 다른 replica의 멤버 이름을 지정하면, 그 노드를 복제 소스로 삼는 cascading replication이 된다.

tags:
  replicatefrom: node2

clonefrom과는 역할이 다르다. clonefrom은 “나를 복사 소스로 써도 좋다"고 알리는 tag고, replicatefrom은 “나는 저 노드에서 복제하겠다"고 선언하는 tag다. 전자는 초기 데이터 복사의 소스 선택에, 후자는 어느 노드에서 streaming으로 WAL을 받을지에 작용한다. replica를 새로 만드는 시점에 두 tag가 어떻게 상호작용하는지는 공식 문서에 상세가 없다.

백업 도구로 대체

replica를 만들 때마다 소스 노드에서 전체 복사를 뜨는 대신, 백업 저장소에서 복원하도록 바꾸는 구성이 널리 쓰인다. 공식 문서의 pgBackRest 예시가 이 패턴이다.

postgresql:
  create_replica_methods:
    - pgbackrest
    - basebackup
  pgbackrest:
    command: /usr/bin/pgbackrest --stanza=demo --delta restore
    keep_data: True
    no_params: True
  basebackup:
    max-rate: '100M'

--delta restore는 checksum 비교로 재사용 가능한 파일을 남기므로 keep_data: True와 짝을 이루고, pgBackRest는 --scope 같은 Patroni 인자를 받지 않는 외부 명령이므로 no_params: True로 전달을 끈다. WAL-E 예시도 문서에 있다.

postgresql:
  create_replica_methods:
    - wal_e
    - basebackup
  wal_e:
    command: patroni_wale_restore
    no_leader: 1
    envdir: /etc/wal_e/env
    use_iam: 1

두 예시 모두 마지막에 basebackup을 fallback으로 병기한다. 백업 저장소 복원이 실패해도 소스 노드 직접 복사로 replica를 만들 수 있게 하는 안전망이다. WAL archive 연동을 포함한 백업 도구 통합의 전체 그림은 10.5 백업 도구 통합에서 다룬다.

정리

  • replica 생성은 create_replica_methods 목록을 순서대로 시도하고 exit 0에서 멈춘다. 전부 실패하면 다음 loop cycle에 재시도한다.
  • Patroni는 --scope, --datadir, --role=replica, --connstring 네 인자를 전달하고, no_leader, keep_data, no_params로 계약을 조정한다.
  • 기본 basebackup의 소스는 leader이며 clonefrom tag로 바꾼다. 백업 도구로 대체할 때는 basebackup을 fallback으로 남겨 두는 구성이 일반적이다.