제가 서비스를 운영하면서 직접 겪은 . . .
primary 1대 + standby 3대 구성부터 upstream 변경, 그리고 장애 시 promote까지
단순 이론 말고 실제 삽질하면서 경험한 내용을 정리해서 작성해보았습니다!
1️⃣ 4노드 HA 구성
목표 구조
기존 프로젝트에서는 primary 와 standby 로 구성된 ha 상태의 DB 서비스를 운영하고 있었습니다.
이해를 돕기 위해 각각의 DB 01, 02, 03, 04 같이 순번을 붙혀 설명하겠습니다.
db01 (primary)
└─ db02 (standby)
그러던 중 DB 서버의 OS 업그래이드를 하게 되었습니다.
In-place 업그레이드를 진행하면 라이브러리나 DB extension 이 깨질 수 있기 때문에
DB를 먼저 Standby 로 복제를 떠서 운영하다가 진행하는 것으로 구성하였습니다.
db01 (primary)
├─ db02 (standby - 기존)
├─ db03 (standby - 신규 OS)
└─ db04 (standby - 신규 OS)
기본 구성 흐름
1. standby clone (db03, db04)
먼저 db03 과 db04 를 standby 로 등록을 하기 위해 db01(primary) 데이터를 clone 떠서 데이터를 동기화 시킵니다.
repmgr standby clone -h db01 -U repmgr -d experdb -F
2. standby 기동 후 standby 등록
# DB 기동
pg_ctl start
# Standby 등록
repmgr standby register -F
3. 결과 확인
[experdb@db04 etc]$ repmgr service status
WARNING: following problems with command line parameters detected:
database connection parameters not required when executing SERVICE STATUS
ID | Name | Role | Status | Upstream | repmgrd | PID | Paused? | Upstream last seen
----+------+---------+-----------+----------+-------------+--------+---------+--------------------
1 | db01 | primary | * running | | running | 235708 | no | n/a
2 | db02 | standby | running | db01 | running | 126832 | no | 0 second(s) ago
3 | db03 | standby | running | db01 | not running | n/a | n/a | n/a
4 | db04 | standby | running | db01 | not running | 28389 | no | 8 second(s) ago
📌 내부 동작 이해 (핵심)
Replication은 데이터 복사가 아니라 WAL replay입니다.
# INSERT → WAL 기록 → standby 전달 → standby에서 replay
db01 → WAL → db02
→ WAL → db03
→ WAL → db04
2️⃣ 클러스터 분리 (DB01/02 vs DB03/04)
OS 작업 준비가 되면 기존 서비스와 분리해야 합니다.
📌 목표 구조
서버 db01 과 db02, 서버 db03 과 db04 를 분리하여 운영하고
기존 db01, 02 에 붙어있던 서비스를 db03, 04 로 전반적인 교체 작업을 진행해야 합니다.
여기에서 클러스터 분리에 대하여 집중 공략하겠습니다!
클러스터 A
db01 → db02
클러스터 B
db03 → db04
1. 기존 primary(db01) 중지
primary 가 2개 생성되면 split-brain 이 발생하기 때문에
기존 사용하는 primary 를 다운 시킵니다.
pg_ctl stop
2. db03을 primary로 승격
기존 standby 였던 db03 을 promote 를 통해 primary 로 승격시킵니다.
pg_ctl promote
3. db04를 db03에 붙이기
- db04번의 upstream-node-id 변경(기존 primary가 db01로 잡혀있기 때문에 변경 시 -F 옵션을 줘서 강제로 변경)
repmgr standby register -F --upstream-node-id=3
- postgresql.conf 파일에 옵션 추가(혹은 postgresql.auto.conf)
primary_conninfo = 'host=db03 port=5432 user=repmgr application_name=db04 connect_timeout=2'
primary_slot_name = 'repmgr_slot_4'
- postgresql.conf 파일에 shared_preload_libraries 옵션 추가
shared_preload_libraries = 'repmgr'
4. repmgr 메타데이터 정리
db03 기준
DELETE FROM repmgr.nodes WHERE node_id IN (1,2);
db01 기준
DELETE FROM repmgr.nodes WHERE node_id IN (3,4);
📌 결과
repmgr nodes 에서 각각의 클러스터를 삭제함으로써 이중화 구성을 완전히 분리시킵니다.
db01 → db02
db03 → db04
3️⃣ 장애 발생 (WAL 폭증 → Disk 90%)
이중화 구성을 분리하여 운영을 한지 이틀이 지난 시점에 Disk 가 90프로 이상 차는 이슈가 발생하였습니다.(총 2TB 중 1.8TB)
디스크 사용량을 확인해보니 WAL 디렉토리가 비정상적으로 커져서 Disk 이슈가 발생한 것이였습니다.
정상적인 구조라면 WAL 은 아카이브 푸시를 진행한 뒤 checkpoint 이후 재사용 혹은 삭제가 되며 자동으로 정리가 되어야하지만 해당 캐이스는 특정한 이슈에 의하여 wal이 정리되지 않고 쌓이고 있었습니다.
📌 원인 추적
① DB 로그 확인
먼저 아카이브 푸시가 정상적으로 동작하는지 확인하기 위하여 db 로그를 확인하였습니다.
wal 은 백업을 받기 위하여 아카이브에 데이터를 복제하게 되는데 이 때 아카이브 푸시가 정상적으로 발생하지 않으면 아직 데이터를 필요로 하는것으로 판단하여 wal 을 정리를 하지 않기 때문입니다.
하지만 로그를 확인해본 결과 아카이브 푸시는 정상적으로 success 가 떨어지고 있었습니다.
② slot 확인(원인 발견!)
db03 에서 wal 이 계속 차고있었기 때문에 standby 에 데이터를 전달하는 과정에서
정상적으로 동작하는지 검토하기 위하여 slot 을 확인해보았습니다.
SELECT slot_name, active, restart_lsn
FROM pg_replication_slots;
확인해보았을 때 db03 에서 db02 의 slot 정보를 가지고 있었고,
db02 가 wal 을 아직 필요로 한다고 postgresql db 엔진에서 판단하여 wal 을 삭제하지 않고 있던 것이였습니다.
1. replication slot 존재
↓
2. slot의 restart_lsn 확인
↓
3. "이 LSN 이후 WAL은 반드시 필요"로 판단
↓
4. checkpoint 발생
↓
5. WAL 정리 시도
↓
6. restart_lsn보다 이전 WAL만 삭제 가능
↓
7. restart_lsn이 뒤로 안 움직이면 WAL 삭제 불가
↓
8. WAL 계속 누적
4️⃣ 해결 (Slot 삭제 + Checkpoint)
inactive slot 때문에 wal 이 정리되지 않는 것을 확인하였고 해당 slot 을 삭제하고 wal 을 정리하기로 판단하였습니다.
1. slot 삭제
SELECT pg_drop_replication_slot('repmgr_slot_2');
2. checkpoint 실행
CHECKPOINT;
📌 결과
이로서 wal이 정상 크기로 감소하는 것을 확인하였고 서비스 정상화 확인 완료하였습니다!
du -sh pg_wal
📌 정리!
“WAL은 쌓이는 게 아니라, 삭제 조건이 막혀서 남는다.”
대부분의 WAL 폭증 문제는 replication slot 하나에서 시작된다.
(작업은 1~2주간 정상동작 확인되었을 때 마무리된다!)
출처