멀티 리전에서 Patroni H/A 운용하기 — Part 4: Split-Brain 방지 전략
멀티 리전 HA에서 진짜 위험은 장애 자체가 아니라, 두 노드가 동시에 Primary로 쓰기를 받는 Split-Brain이다. DCS(etcd) Leader Lock과 Quorum, Linux Watchdog, STONITH(외부 Fencing)의 3단계 방어 레이어 구조를 설명하고, TTL·loop_wait·safety_margin 튜닝 원칙, DCS Failsafe Mode 주의사항, 실제 Split-Brain 발생 시 긴급 대응 절차까지 정리한다.
시리즈 구성 — 멀티 리전에서 Patroni H/A 운용하기
- Part 1 — 기초 개념과 아키텍처 설계 원칙
- Part 2 — 동기 복제 멀티 DC 구성 실습
- Part 3 — 비동기 복제 + Standby Cluster 구성 실습
- Part 4 — Split-Brain 방지 전략 (현재 편)
- Part 5 — 장애 대응 Runbook 및 DR 훈련 시나리오
- Part 6 — 모니터링, 운영 자동화 및 Best Practices
목차
- Split-Brain은 왜 그렇게 위험한가?
- Split-Brain이 실제로 발생하는 시나리오
- Patroni의 3단계 방어 레이어 구조
- Layer 1 — DCS(etcd) Leader Lock과 Quorum
- Layer 2 — Linux Watchdog
- Layer 3 — STONITH (클라우드 Fencing)
- Bonus: DCS Failsafe Mode
- 방어 레이어 타임라인 시각화
- TTL, loop_wait, safety_margin 튜닝 가이드
- 흔히 겪는 트러블슈팅
- 참고 자료
1. Split-Brain은 왜 그렇게 위험한가?
Split-Brain이란 클러스터 내에서 두 개 이상의 노드가 동시에 Primary(Leader)라고 믿는 상태다. 이 상태가 발생하면 두 노드가 동시에 클라이언트의 쓰기 요청을 수락하게 되고, 데이터는 서로 다른 방향으로 갈라진다(Diverging Timeline).
정상 상태:
Client --> [ Primary A (서울) ] --WAL--> [ Replica B (도쿄) ]
Split-Brain 상태:
Client --> [ Primary A (서울) ] --writes--> Timeline #3
Client --> [ Primary B (도쿄) ] --writes--> Timeline #3 (분기됨!)
두 타임라인은 절대로 자동 병합되지 않는다 -> 데이터 영구 손실
이 상황이 단순 다운타임보다 위험한 이유는 다음과 같다.
| 결과 | 설명 |
|---|---|
| 데이터 충돌 | 동일 PK에 서로 다른 값이 기록됨 |
| 데이터 손실 | 분기된 타임라인의 트랜잭션은 복구 불가 |
| 참조 무결성 파괴 | FK 관계가 두 노드에서 서로 다른 상태로 커밋됨 |
| 감사/규제 위반 | 금융·의료 데이터의 일관성 보장 불가 |
| 비즈니스 신뢰 붕괴 | 고객 데이터 불일치로 인한 법적 책임 발생 가능 |
Split-Brain은 발생 후 감지도 어렵다. 양쪽 노드 모두 정상처럼 보이며 로그에도 에러가 없다. 실제 피해는 한참 후 애플리케이션 레벨의 데이터 불일치로 발견된다.
2. Split-Brain이 실제로 발생하는 시나리오
시나리오 1: Patroni 프로세스 크래시 (가장 흔함)
t=0s Primary A가 etcd에 Leader Key 갱신 성공 (TTL=30s)
t=5s Patroni 프로세스가 OOM으로 강제 종료 (kill -9)
t=5s PostgreSQL은 아직 살아있음 -> 클라이언트 쓰기 계속 수락
t=15s etcd TTL 만료 -> Replica B가 리더 선출 레이스 진행
t=17s Replica B -> Primary B로 승격
t=17s Primary A(PG) + Primary B(PG) 동시 쓰기 수락 = SPLIT-BRAIN!
t=30s Watchdog 타임아웃 -> Primary A 노드 강제 재부팅 <- 방어선
Patroni 프로세스가 죽어도 PostgreSQL은 독립적으로 살아 있기 때문에, Watchdog 없이는 etcd TTL이 만료되는 순간부터 새 Primary 승격까지의 시간 동안 Split-Brain 상태가 된다.
시나리오 2: 네트워크 파티션 (멀티 리전에서 가장 위험)
etcd가 DC1에 2개, DC2에 1개 배치된 경우 파티션 발생 시 DC1이 Quorum을 보유하므로 Primary A가 계속 Leader Key를 갱신할 수 있다. DC2는 Quorum이 없어 승격이 불가능하다 — Split-Brain 없음.
반면 etcd가 DC1에 1개, DC2에 2개 몰려 있다면:
t=0s 네트워크 파티션 발생
t=0s DC1 etcd-1: Quorum 잃음 -> Primary A의 Leader Key 갱신 실패
t=10s DC1: Patroni가 PostgreSQL 강등(Demote) 시작
t=10s DC2 etcd-2,3: Quorum 유지 -> Replica B 승격 시도
t=12s DC2: Primary B 승격 완료
t=12s DC1: PostgreSQL 아직 쓰기 수락 중 = SPLIT-BRAIN! (Watchdog 없으면)
시나리오 3: VM Hypervisor Pause (클라우드 환경 특유)
AWS/GCP 같은 클라우드 환경에서 하이퍼바이저가 VM을 일시 정지(Live Migration, Snapshot)시키는 동안 Patroni가 응답하지 못할 수 있다. VM이 다시 깨어나면 Patroni는 자신이 잠시 멈춘 것을 모르고 Leader Lock 갱신을 시도하지만, 이미 TTL이 만료되어 새 Primary가 선출된 상태일 수 있다.
3. Patroni의 3단계 방어 레이어 구조
Patroni는 Split-Brain을 막기 위해 방어 레이어를 겹겹이 쌓는다. 각 레이어는 독립적으로 동작하며, 앞 레이어가 실패해도 다음 레이어가 보호한다.
4. Layer 1 — DCS(etcd) Leader Lock과 Quorum
가장 기본적인 방어선은 etcd의 Leader Lock(TTL 기반 키)이다. Primary 노드는 매 loop_wait초마다 etcd에 Leader Key를 갱신(CAS: Compare-And-Swap)한다. 갱신에 실패하면 Patroni는 즉시 PostgreSQL을 강등시킨다.
etcd Quorum이 Split-Brain을 막는 원리
3-node etcd (DC1=서울, DC2=도쿄, DC3=싱가포르):
정상: [서울 etcd] <-- Raft --> [도쿄 etcd] <-- Raft --> [싱가포르 etcd]
(Quorum = 2/3 이상 동의 필요)
DC1 장애:
도쿄 + 싱가포르 = 2/3 Quorum 유지 -> 새 Leader Key 발급 가능 (OK)
서울 홀로 남음 = 1/3 Quorum 부족 -> Leader Key 갱신 불가 -> 강등 (OK)
DC1+DC2 동시 장애:
싱가포르 홀로 = 1/3 Quorum 부족 -> 아무도 새 Primary 될 수 없음
(가용성 희생, Split-Brain 없음) (OK)
etcd TTL 관련 핵심 파라미터
# patroni.yml -> bootstrap.dcs 섹션
bootstrap:
dcs:
# TTL: Leader Key의 유효 시간(초). 이 시간 동안 갱신 없으면 Lock 만료
ttl: 30
# loop_wait: Patroni의 HA 루프 실행 간격(초)
# Primary는 매 loop_wait초마다 Leader Key 갱신 시도
loop_wait: 10
# retry_timeout: DCS 연결 실패 시 재시도 제한 시간(초)
# 이 시간 내에 DCS 연결이 복구되지 않으면 Primary 강등
retry_timeout: 10
파라미터 관계 공식 (ttl=30, safety_margin=5, loop_wait=10 기준):
최소 쓰기 차단 보장 시간 = TTL - safety_margin - loop_wait
= 30 - 5 - 10 = 15초
Primary가 DCS와 통신이 끊기더라도 최소 15초 안에 쓰기가 차단되어야 한다.
etcd 배치 황금 규칙
| 배치 방식 | Quorum 유지 | Split-Brain 위험 | 권장 여부 |
|---|---|---|---|
| DC1에 3개 몰아넣기 | DC1 장애 시 전체 중단 | 없음 | 비권장 (SPOF) |
| DC1에 2개, DC2에 1개 | DC1 장애 시 중단 | DC2 분리 시 위험 | 주의 |
| 3 DC에 1개씩 균등 배포 | DC 1개 장애에도 유지 | 없음 | 권장 |
| 5개를 3 DC에 2-2-1 배포 | DC 2개 동시 장애도 허용 | 없음 | 최고 |
5. Layer 2 — Linux Watchdog
DCS 통신 실패로 Patroni가 PostgreSQL을 강등시키려 할 때, Patroni 자신이 크래시되거나 응답 불가 상태라면 PostgreSQL을 멈추지 못한다. 이 시나리오를 막는 것이 Watchdog이다.
Patroni는 Primary로 승격되기 전에 Watchdog을 먼저 활성화한다. watchdog.mode: required인 경우 Watchdog 활성화가 실패하면 노드는 Leader가 되기를 거부한다.
Watchdog 동작 원리
정상 동작:
Patroni -> /dev/watchdog에 keepalive 신호 전송 (매 loop_wait마다)
Watchdog 타이머 리셋 -> 시스템 정상 유지
비정상 동작 (Patroni 크래시/무응답):
Patroni -> keepalive 신호 끊김
Watchdog 타이머 만료 (TTL - safety_margin = 25초)
Linux 커널 -> 노드 강제 재부팅 (SIGKILL 수준)
PostgreSQL 종료 -> 쓰기 불가 상태 전환 (OK)
Step 1 — Softdog 커널 모듈 활성화
# 모든 Primary 후보 노드에서 실행 (root)
modprobe softdog
# Patroni 실행 유저(postgres)에게 /dev/watchdog 권한 부여
chown postgres:postgres /dev/watchdog
# 재부팅 후에도 유지되도록 영구 설정
echo "softdog" >> /etc/modules-load.d/patroni-watchdog.conf
# 권한 자동 부여 (udev rule)
cat > /etc/udev/rules.d/99-patroni-watchdog.rules <<'EOF'
KERNEL=="watchdog", OWNER="postgres", GROUP="postgres", MODE="0600"
EOF
# 확인
ls -la /dev/watchdog
# crw------- 1 postgres postgres 10, 130 Apr 26 10:00 /dev/watchdog
테스트 환경 팁: 실제 재부팅 없이 Watchdog 동작을 확인하려면
soft_noboot=1옵션을 사용한다. 이 경우 타임아웃 시 재부팅 대신 커널 로그(dmesg)에 경고 메시지만 남긴다.
# 테스트용: 재부팅 없이 로그만 기록
modprobe softdog soft_noboot=1
Step 2 — patroni.yml에 Watchdog 설정 추가
# /etc/patroni/patroni.yml
watchdog:
# mode 옵션:
# off - Watchdog 비활성화 (기본값, 프로덕션 비권장)
# automatic - 가능하면 사용, 없어도 Leader 가능
# required - 반드시 Watchdog 필요, 없으면 Leader 거부 (최고 보안)
mode: required # 프로덕션에서는 required 권장
device: /dev/watchdog # Watchdog 디바이스 경로
# safety_margin: TTL 만료 몇 초 전에 Watchdog을 타임아웃시킬지
# 기본값: 5초
# -1로 설정 시 Watchdog 타임아웃 = TTL / 2 (절대 보장 모드)
safety_margin: 5
Step 3 — Hardware Watchdog (온프레미스 권장)
클라우드 환경에서는 Softdog으로 충분하지만, 온프레미스 베어메탈 서버에서는 커널 자체가 행(Hang)에 걸리는 경우 Softdog도 동작하지 않는다. 이때는 하드웨어 Watchdog을 사용한다.
# IPMI 기반 하드웨어 Watchdog (HP iLO, Dell iDRAC 등)
# 디바이스 확인
ls /dev/watchdog*
# /dev/watchdog0 <- 하드웨어 Watchdog
# Patroni 설정에서 디바이스 경로만 변경
# watchdog.device: /dev/watchdog0
# watchdog 상태 확인 (wdctl 패키지)
apt-get install -y watchdog
wdctl /dev/watchdog0
Watchdog 동작 확인
# Patroni 로그에서 Watchdog 활성화 메시지 확인
journalctl -u patroni | grep -i watchdog
# 정상 출력 예시:
# INFO: Software Watchdog activated with 25 second timeout, timing slack 15 ms
# INFO: Watchdog activated successfully
# Watchdog 상태 직접 확인 (Patroni REST API)
curl -s http://localhost:8008/patroni | python3 -m json.tool | grep watchdog
# "watchdog_failed": false
6. Layer 3 — STONITH (클라우드 Fencing)
STONITH(Shoot The Other Node In The Head)는 문제 노드를 외부에서 강제로 종료하는 메커니즘이다. Watchdog이 노드 내부의 자기 방어라면, STONITH는 외부에서 가하는 강제 격리다. 2DC Standby Cluster 승격 시나 Watchdog이 없는 환경에서 Split-Brain 방지를 위한 최후의 수단이다.
AWS EC2 STONITH 구현 예시
#!/usr/bin/env python3
# /usr/local/bin/stonith-aws.py
# 사용법: stonith-aws.py <instance-id> [stop|terminate]
import sys
import boto3
import logging
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s')
logger = logging.getLogger(__name__)
def stonith_instance(instance_id: str, action: str = "stop") -> bool:
"""
AWS EC2 인스턴스를 강제 중지/종료한다.
action: "stop" (재사용 가능) 또는 "terminate" (완전 삭제)
"""
ec2 = boto3.client('ec2')
try:
logger.info(f"STONITH: {action} 실행 대상 인스턴스 {instance_id}")
if action == "terminate":
response = ec2.terminate_instances(InstanceIds=[instance_id])
state = response['TerminatingInstances'][0]['CurrentState']['Name']
waiter_name = 'instance_terminated'
else:
response = ec2.stop_instances(
InstanceIds=[instance_id],
Force=True # 강제 종료 (정상 셧다운 절차 생략)
)
state = response['StoppingInstances'][0]['CurrentState']['Name']
waiter_name = 'instance_stopped'
logger.info(f"STONITH 성공: 인스턴스 {instance_id} 상태 -> {state}")
waiter = ec2.get_waiter(waiter_name)
waiter.wait(
InstanceIds=[instance_id],
WaiterConfig={'Delay': 5, 'MaxAttempts': 24} # 최대 2분 대기
)
logger.info(f"STONITH 완료: 인스턴스 {instance_id} 완전 중지 확인")
return True
except Exception as e:
logger.error(f"STONITH 실패: {e}")
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: stonith-aws.py <instance-id> [stop|terminate]")
sys.exit(1)
instance_id = sys.argv[1]
action = sys.argv[2] if len(sys.argv) > 2 else "stop"
success = stonith_instance(instance_id, action)
sys.exit(0 if success else 1)
STONITH 스크립트를 실제 운영에 적용하기 전에 반드시 세 가지를 확인해야 한다. 첫째, 스크립트를 실행하는 IAM Role/서비스 계정에 EC2 Stop/Terminate 권한이 있는지. 둘째, 잘못된 인스턴스 ID가 들어올 경우를 대비한 검증 로직이 있는지. 셋째, 실제 장애가 아닌 상황에서 오작동하지 않도록 테스트 환경에서 충분히 검증되었는지.
Patroni on_stop Callback으로 STONITH 자동화
Patroni는 역할 변경 시 실행할 콜백 스크립트를 지원한다. on_stop 이벤트를 활용하면 Primary가 강등될 때 즉시 클라이언트 연결을 차단할 수 있다.
# patroni.yml
postgresql:
callbacks:
on_stop: /usr/local/bin/patroni-on-stop.sh
on_role_change: /usr/local/bin/patroni-on-role-change.sh
#!/bin/bash
# /usr/local/bin/patroni-on-stop.sh
# 인자: $1=action(on_stop), $2=role(master/replica), $3=scope
ACTION="$1"
ROLE="$2"
if [ "$ROLE" = "master" ]; then
logger -t patroni-callback "Primary 강등 감지: 5432 포트 즉시 차단"
iptables -I INPUT -p tcp --dport 5432 -j DROP
iptables -I OUTPUT -p tcp --sport 5432 -j DROP
sleep 30
iptables -D INPUT -p tcp --dport 5432 -j DROP
iptables -D OUTPUT -p tcp --sport 5432 -j DROP
fi
GCP / Azure / 온프레미스 STONITH 힌트
# GCP: gcloud CLI를 이용한 인스턴스 강제 중지
gcloud compute instances stop INSTANCE_NAME \
--zone=asia-northeast3-a \
--project=MY_PROJECT
# Azure: az CLI를 이용한 VM 강제 중지
az vm stop \
--resource-group MY_RG \
--name MY_VM \
--no-wait
# 온프레미스: IPMI를 이용한 전원 차단
ipmitool -H 10.1.0.10 -U admin -P password \
chassis power off
7. Bonus: DCS Failsafe Mode
DCS Failsafe Mode는 Split-Brain 방지와는 방향이 반대다. Split-Brain이 Primary가 너무 오래 살아있는 문제라면, DCS Failsafe Mode는 DCS가 일시적으로 불안정할 때 Primary가 불필요하게 강등되는 문제를 해결하기 위해 설계되었다.
DCS Failsafe Mode의 동작 원리
DCS Failsafe Mode가 활성화된 상태에서 Primary가 DCS에 Leader Lock 갱신에 실패하면, 즉시 강등되는 대신 모든 클러스터 멤버에게 REST API(POST /failsafe)를 통해 직접 생존 신호를 확인한다. 모든 멤버가 응답하면 Primary는 계속 운영되며, 단 하나의 멤버라도 응답하지 않으면 즉시 강등된다.
DCS Failsafe Mode 활성화
patronictl -c /etc/patroni/patroni.yml edit-config
# Dynamic Configuration 변경
failsafe_mode: true
# 활성화 전 확인 사항:
# 1. 모든 클러스터 멤버가 동일 버전의 Patroni를 실행 중인가?
# 2. 모든 멤버가 REST API(8008 포트)로 서로 통신 가능한가?
# 3. 멤버 수가 짝수인가? (짝수이면 /failsafe 체크가 더 엄격해짐)
DCS Failsafe Mode 사용 시 주의사항
DCS Failsafe Mode는 quorum 설계, watchdog, STONITH를 대체하는 기능이 아니다. 아래 상황에서는 사용에 주의해야 한다.
사용 비권장 상황:
- Kubernetes 환경에서 K8s API가 DCS로 쓰일 때 (K8s API 불안정 빈번)
- 클러스터 멤버 간 직접 REST API 통신이 방화벽으로 막혀 있을 때
- 멤버 수가 2개뿐인 소규모 클러스터 (단일 멤버 장애 = 강등)
효과적인 상황:
- etcd가 전용 노드로 운영되고 네트워크는 안정적인 환경
- 클러스터 멤버가 3개 이상이고 AZ 분산 배치된 환경
- DCS 유지보수 중 Primary 강등을 방지해야 할 때
8. 방어 레이어 타임라인 시각화
아래는 Primary 노드가 DCS와 단절되었을 때 각 방어 레이어가 언제, 어떻게 동작하는지를 시간축으로 보여준다. (ttl=30, loop_wait=10, retry_timeout=10, safety_margin=5 기준)
t=0s DCS(etcd)와 통신 단절 감지
t=0-10s Patroni: retry_timeout 동안 재연결 시도
t=10s 재연결 실패 -> Patroni: PostgreSQL 강등(Demote) 시작
[!] Watchdog keepalive 중지 (Patroni 응답 불가일 경우)
t=25s [!] Watchdog 타임아웃 (TTL - safety_margin = 30 - 5)
-> 커널이 노드 강제 재부팅 -> PostgreSQL 강제 종료
t=30s [!] etcd TTL 만료 -> 다른 노드가 Leader Race 시작
t=32s 새 Primary 승격 완료 -> 정상 복구
[Layer 1] etcd TTL (30s): |<----------- 30s ----------->|
[Layer 2] Watchdog (25s): |<--------- 25s -------->|
[Layer 3] STONITH: 운영자 수동 실행 (필요 시)
9. TTL, loop_wait, safety_margin 튜닝 가이드
멀티 리전 환경에서는 네트워크 지연(RTT)이 높기 때문에 기본값으로는 불안정할 수 있다.
튜닝 원칙
1. loop_wait >= 리전 간 RTT x 3 이상
2. retry_timeout >= loop_wait
3. ttl >= loop_wait x 2 + retry_timeout
4. safety_margin = ttl - loop_wait - retry_timeout - 여유(5s)
5. watchdog timeout = ttl - safety_margin
환경별 권장 설정
# -- 단일 DC (로컬, RTT < 1ms) --------------------------------
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
# watchdog timeout = 30 - 5 = 25초
watchdog:
mode: required
safety_margin: 5
# -- 국내 멀티 리전 (서울-부산, RTT ~10ms) ---------------------
bootstrap:
dcs:
ttl: 40
loop_wait: 15
retry_timeout: 15
watchdog:
mode: required
safety_margin: 10 # watchdog timeout = 40 - 10 = 30초
# -- 글로벌 멀티 리전 (서울-싱가포르, RTT ~60ms) ---------------
bootstrap:
dcs:
ttl: 60
loop_wait: 20
retry_timeout: 20
watchdog:
mode: required
safety_margin: 20 # watchdog timeout = 60 - 20 = 40초
# -- 절대 보장 모드 (Split-Brain 불허) -------------------------
watchdog:
mode: required
safety_margin: -1 # watchdog timeout = ttl / 2
TTL과 loop_wait를 높이면 Split-Brain 방지는 강화되지만 장애 감지 및 자동 페일오버 시간이 길어진다. 비즈니스 요구사항(RTO)과 균형을 맞춰야 한다.
현재 설정 확인 및 적용
# 현재 DCS 동적 설정 확인
patronictl -c /etc/patroni/patroni.yml show-config
# TTL/loop_wait 변경 (중단 없이 실시간 적용)
patronictl -c /etc/patroni/patroni.yml edit-config
# ttl, loop_wait, retry_timeout 항목 수정 후 저장
# 변경 사항 즉시 확인
patronictl -c /etc/patroni/patroni.yml list
10. 흔히 겪는 트러블슈팅
문제 1: Watchdog 활성화 실패로 노드가 Leader 거부
CRITICAL: watchdog.device /dev/watchdog not found
WARNING: Could not activate watchdog. Refusing to be promoted
# softdog 모듈 로드 확인
lsmod | grep softdog
# softdog가 없으면:
modprobe softdog
# /dev/watchdog 존재 여부 확인
ls -la /dev/watchdog
# Patroni 실행 유저 권한 확인 (Owner: postgres여야 함)
stat /dev/watchdog
chown postgres:postgres /dev/watchdog
# udev rule 재로드
udevadm control --reload-rules && udevadm trigger
문제 2: DCS 일시 불안정으로 잦은 Primary 강등
INFO: DCS not accessible, stopping Postgres
INFO: demoted self because DCS is not accessible and i had the leader lock
# 방법 1: DCS Failsafe Mode 활성화 (DCS 불안정 허용)
patronictl -c /etc/patroni/patroni.yml edit-config
# failsafe_mode: true 추가
# 방법 2: retry_timeout 상향 조정 (일시적 DCS 장애에 더 관대하게)
# retry_timeout: 15 -> retry_timeout: 30
patronictl -c /etc/patroni/patroni.yml edit-config
문제 3: 네트워크 파티션 후 재연결 시 구 Primary가 승격 시도
WARNING: Stale leader key found, ignoring
INFO: following a different leader because my replay LSN is behind
이것은 정상 동작이다. Patroni는 재연결 후 자신의 LSN이 현재 Leader보다 낮으면 자동으로 Replica로 합류한다. pg_rewind가 실패한다면:
# pg_rewind 없이 강제 재초기화
patronictl -c /etc/patroni/patroni.yml reinit \
pg-seoul-cluster pg-seoul-1 --force
문제 4: 두 노드가 동시에 Primary라고 주장 (실제 Split-Brain)
# -- 긴급 대응 절차 -----------------------------------------
# 1. 두 Primary 중 LSN이 낮은 노드(구 Primary)를 즉시 중지
# 어느 쪽이 구 Primary인지 확인
psql -h 10.1.0.10 -U postgres -c "SELECT pg_current_wal_lsn(), pg_is_in_recovery();"
psql -h 10.2.0.10 -U postgres -c "SELECT pg_current_wal_lsn(), pg_is_in_recovery();"
# 2. LSN이 낮은 노드 즉시 중지
systemctl stop patroni
systemctl stop postgresql
# 3. 해당 노드의 5432 포트 차단
iptables -I INPUT -p tcp --dport 5432 -j DROP
# 4. 살아있는 Primary의 클러스터 상태 확인
patronictl -c /etc/patroni/patroni.yml list
# 5. 중지된 노드를 Replica로 재초기화
rm -rf /var/lib/postgresql/17/main/*
systemctl start patroni
참고 자료
- Patroni 공식 문서 — Watchdog Support
- Patroni 공식 문서 — DCS Failsafe Mode
- Percona — Patroni Split-Brain Prevention Architecture
- Stormatics — Understanding Split-Brain Scenarios in HA PostgreSQL Clusters
- Medium (Oz) — Avoiding Split-Brain Using Watchdog/softdog (2025)
- Patroni POSETTE 2025 — What is Patroni, really?