PostgreSQL repmgr 스플릿브레인 복구

반응형
PostgreSQL repmgr 스플릿브레인 복구 가이드 (RMAN Duplicate 아님)

PostgreSQL repmgr 스플릿브레인 복구 가이드

PostgreSQL repmgr HA 환경에서 네트워크 단절이나 장애 처리 미흡으로 인해 두 노드가 동시에 primary role을 가지는 스플릿브레인(split-brain) 상황이 발생할 수 있습니다. 이 글은 이미 두 노드 모두 primary 상태가 되어버린 환경에서, 한 노드를 기준 Primary로 확정하고 나머지 노드를 pg_rewind + repmgr standby register로 되살리는 절차를 정리한 기술 가이드입니다.

1️⃣ 장애 상황 및 증상 정리

환경 PostgreSQL + repmgr 기반 2노드 HA(Primary 1대, Standby 1대 구성)
장애 유형 네트워크 단절 또는 장애 조치 과정에서 두 노드가 모두 Primary로 승격된 스플릿브레인(split-brain) 상태
사용자 시도 repmgr standby register -f /home/petagres/repmgr.conf --force 로 Secondary를 강제로 standby로 등록하려 했으나 실패
핵심 증상 - repmgr cluster show 에서 두 노드 모두 primary로 표시
- standby register / clone / rewind 명령이 기대대로 동작하지 않음
- 접근 방향에 따라 타임라인과 WAL LSN이 서로 다른 상태로 분기
중요 포인트
단순히 repmgr standby register --force 만으로는 스플릿브레인 상태가 해결되지 않습니다.
이유는 다음과 같습니다.
  • 각 노드는 로컬 데이터 디렉터리와 repmgr 메타 테이블 기준으로 자신을 primary라고 인식하고 있음
  • repmgr은 실제 인스턴스가 primary로 동작 중인 노드를 강제로 standby로 등록하지 않도록 설계
  • 서로 다른 타임라인 / LSN을 가진 상태에서는 pg_rewind 같은 정합성 작업이 선행되지 않으면 안전한 스탠바이 전환이 불가능

2️⃣ 전체 복구 전략 개요

스플릿브레인 복구의 핵심 전략은 다음 두 가지입니다.

  1. 한 노드만 절대적인 Primary로 확정한다. (가장 최신 WAL LSN을 가진 노드)
  2. 나머지 노드를 완전히 내려서, pg_rewind로 Primary와 데이터를 맞춘 뒤 standby clone + register로 다시 붙인다.

즉, “내가 임의로 secondary로 지정하고 싶다”가 아니라, WAL LSN 기준으로 누가 최신인지 먼저 결정한 뒤, 그 기준에 맞춰 나머지를 되돌리는 절차가 필요합니다.

3️⃣ 1단계 – 진짜 Primary 노드 선택 (LSN 기준)

① 각 노드에서 LSN 확인
psql -U postgres -c "SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0');"
또는 보다 자세히 보고 싶다면:
psql -U postgres -c "SELECT pg_current_wal_lsn();"
② repmgr 메타 정보 확인
repmgr cluster show
  • 여기서는 두 노드 모두 primary 로 나올 수 있으므로, role 출력만 믿지 말고 LSN 값을 기준으로 최신 노드를 선택합니다.

일반적으로 더 큰 LSN 값을 가진 노드가 더 많은 트랜잭션을 반영한 상태이므로, 이 노드를 살릴 Primary로 확정합니다.

4️⃣ 2단계 – Standby로 만들 서버 중지

이제 “Secondary(standby로 만들) 노드”를 정했다면, 그 서버에서 PostgreSQL 서비스를 완전히 중지합니다.

# OS에 따라 서비스 명칭이 다를 수 있음
sudo systemctl stop postgresql-15
# 또는
sudo systemctl stop postgresql

이 시점에서 secondary 노드는 더 이상 트랜잭션을 받아서는 안 됩니다. (추가 변경이 생기면 rewind 기준이 꼬일 수 있음)

5️⃣ 3단계 – repmgr 메타데이터 정리

standby로 만들 노드에서는 repmgr 입장에서 자신을 primary로 기록해 둔 정보를 먼저 정리해야 합니다.

① node_id 확인
repmgr cluster show
② 해당 노드 unregister
repmgr standby unregister --node-id=<SECONDARY_NODE_ID> --force
  • 이 작업은 repmgr 메타 테이블에서 “이 노드는 더 이상 primary/standby로 간주하지 않는다” 라고 지워주는 단계입니다.

6️⃣ 4단계 – pg_rewind 로 데이터 정합성 맞추기

스플릿브레인 해결의 핵심은 pg_rewind 입니다. 이미 분기된 타임라인을 선택한 Primary 노드의 히스토리에 맞게 secondary를 되돌려야 합니다.

pg_rewind \
  --target-pgdata=/var/lib/pgsql/15/data \
  --source-server="host=<PRIMARY_IP> user=repmgr dbname=repmgr"
  • --target-pgdata: 되돌릴 대상(secondary)의 데이터 디렉터리
  • --source-server: 기준이 되는 Primary 서버의 접속 정보
pg_rewind 실행 시 자주 나오는 오류
  • FATAL: WAL log hints are disabledwal_log_hints = on 필요
  • 또는 data checksums 활성화 필요(클러스터 초기화 시 결정)
# postgresql.conf (Primary)
wal_log_hints = on

# 설정 후 Primary 재시작
sudo systemctl restart postgresql-15

7️⃣ 5단계 – repmgr를 통한 standby clone (필요 시)

환경에 따라 pg_rewind 로 충분히 정리되기도 하지만, 스플릿브레인 이후 설정이 꼬여 있거나 재구성이 더 깔끔한 경우 repmgr standby clone 으로 전체를 다시 받는 것이 안전합니다.

repmgr standby clone --force /home/petagres/repmgr.conf
  • recovery 관련 설정(primary_conninfo 등)은 repmgr가 자동으로 생성합니다.
  • 기존 데이터 디렉터리를 덮어쓰는 구조이므로, 꼭 Primary 선택이 올바른지 확인 후 실행해야 합니다.

8️⃣ 6단계 – PostgreSQL 기동 및 standby register

secondary 노드의 데이터 정리가 끝났다면 서비스를 다시 올립니다.

sudo systemctl start postgresql-15
# 서비스 상태 확인
sudo systemctl status postgresql-15

이제 repmgr 관점에서 해당 노드를 standby 로 다시 등록합니다.

repmgr standby register -f /home/petagres/repmgr.conf
  • 이전에는 노드가 primary 로 동작 중이어서 register 가 거부되거나 noop 이었지만, 이제는 standby 모드 + Primary 에 연결된 상태이므로 정상 동작합니다.

9️⃣ 7단계 – 최종 클러스터 상태 확인

repmgr cluster show

정상적인 출력 예시는 다음과 같습니다.

 ID | Name   | Role    | Status    | Upstream | Connection
----+--------+---------+-----------+----------+-----------
 1  | node1  | primary | running   |          | 
 2  | node2  | standby | running   | node1    | conninfo...

이 상태라면 스플릿브레인 상황은 해소되었고, 하나의 Primary와 하나의 Standby 구조로 되돌아온 것입니다.

🔍 왜 standby register --force 만으로는 안 되는가?

repmgr standby register --force 만으로 해결되지 않는 이유는 구조적으로 다음과 같습니다.

  1. 현재 노드가 PostgreSQL 입장에서 primary 모드로 동작 중이면, repmgr은 standby 등록을 거부합니다.
  2. repmgr은 단순 설정 파일이 아니라, 데이터 디렉터리의 pg_control 정보를 함께 참고하여 그 인스턴스가 primary 인지 standby 인지를 판별합니다.
  3. split-brain 이후에는 서로 다른 타임라인과 WAL LSN을 가지게 되므로, pg_rewind 같은 정합성 맞추기 작업 없이 standby로 강제 등록하는 것은 데이터 손상을 야기할 수 있습니다.

따라서,

결론
pg_rewind 없이, 그리고 해당 인스턴스를 실제로 standby 모드로 바꾸지 않은 상태에서는
repmgr standby register --force 만으로는 스플릿브레인을 해결할 수 없습니다.

🔐 7️⃣ 기본 오류 대응 4단계 (공통 보안 관점 체크리스트)

DB 스플릿브레인 복구와 별개로, 서비스 장애·구성 꼬임이 발생했을 때 항상 함께 점검해야 할 공통 보안 체크리스트입니다.

  1. 외부 노출 여부 확인 - DB 포트(예: 5432)가 불필요하게 외부(인터넷)에 노출되어 있지 않은지 확인 - 방화벽 / 보안 그룹 / 로드밸런서 설정 재점검
  2. 역할(서비스) 비활성화 - 장애 노드, 잘못 승격된 노드의 서비스 중지 - 장애 처리 중인 노드에 대한 모니터링 알람 일시 조정
  3. 포트·접속 차단 - 관리 중인 구간 외부에서의 직접 DB 접속 차단 - 필요 시 임시 ACL 정책 적용 (Jump 서버나 Bastion만 허용)
  4. 로그 모니터링 및 사후 분석 - PostgreSQL 로그, repmgr 로그, 시스템 로그(journal)를 함께 분석 - 동일 증상이 재발하지 않도록 장애 재현 & 재발 방지 대책 수립
반응형
LIST