핵심 요약
4.2TB 운영 DB(PG14)를 PG18로 옮겼다. 다운타임 약 11초(컷오버), 데이터 유실 0. 논리적 복제 + 시퀀스 보정 + pgbouncer 핫스왑이 핵심.
1. 왜 논리적 복제인가
| 방법 | 다운타임 | 위험 |
|---|---|---|
| pg_dump / pg_restore | 4시간+ | 낮음 |
| pg_upgrade --link | 30~60분 | 중 (롤백 어려움) |
| 논리적 복제 | 수초 | 중 (시퀀스·DDL 주의) |
| 물리적 복제 + 같은 버전 | 수초 | 낮음 (메이저 업그레이드 불가) |
2. 사전 점검 — PG18의 새 기능 영향
- io_uring 기본 활성: 커널 5.15+ 필요
- UUIDv7 빌트인: 새 인덱스 권장
- SKIP LOCKED + RETURN OLD/NEW: 큐 패턴 단순화 가능
- logical replication 자동 슬롯 동기화: 페일오버 시 슬롯 손실 방지
3. 단계별 절차
1단계: PG18 신규 인스턴스 준비
# 동일 익스텐션 설치 (pgvector, postgis 등)
# wal_level = logical
# max_replication_slots = 10
# max_wal_senders = 10
2단계: 초기 스키마 복사
# 14에서 스키마만 덤프 (호환성 확인)
pg_dump -h pg14 --schema-only --no-publications --no-subscriptions \
-d app | psql -h pg18 -d app
# pgvector 같은 익스텐션은 양쪽 버전 호환 확인
3단계: PUBLICATION + SUBSCRIPTION
-- 14 (publisher)
CREATE PUBLICATION app_pub FOR ALL TABLES;
-- 18 (subscriber)
CREATE SUBSCRIPTION app_sub
CONNECTION 'host=pg14 dbname=app user=replicator'
PUBLICATION app_pub
WITH (copy_data = true, streaming = parallel);
4.2TB 초기 카피에 PG18에선 약 9시간 (스트리밍 병렬 덕). 대용량 테이블은 별도 publication으로 분리해 병렬 카피.
4단계: 시퀀스 보정 — 가장 자주 빠뜨림
-- 논리적 복제는 시퀀스를 동기화하지 않는다!
-- 컷오버 직전, 14에서 모든 시퀀스 last_value를 18로 적용
SELECT schemaname, sequencename,
pg_sequence_last_value(oid)
FROM pg_sequences;
-- 18에서
SELECT setval('users_id_seq', 9382475, true);
-- ... 모든 시퀀스
5단계: 컷오버 (다운타임 시작)
- 앱 traffic 차단 (pgbouncer pause)
- 14의 모든 트랜잭션 완료 대기 (1~3초)
- 구독 lag 확인 = 0 (1~2초)
- 시퀀스 setval (3초)
- pgbouncer config 변경 → PG18 가리키기
- pgbouncer resume (1초)
총 11초. 사용자 입장에서 잠깐 지연으로 보임.
4. 함정 7가지
① 시퀀스 미동기화
위에서 다룬 가장 흔한 함정. 자동화 스크립트 필수.
② TRUNCATE 미복제 (옵션 따라)
기본 publication은 TRUNCATE 복제 안 함. 운영 중 TRUNCATE 안 쓰면 문제 없지만, 확인.
③ DDL 미복제
ALTER TABLE 같은 DDL은 복제 안 됨. 컷오버 전 DDL 동결 정책 필수. PG18은 옵션으로 일부 DDL 복제 가능.
④ 큰 트랜잭션
1만 행 update 한 트랜잭션이 슬롯에 쌓이면 lag 폭증. streaming=parallel 옵션이 PG14→18 조합에서 동작 확인 (publisher 측 14가 minimum 버전).
⑤ UNLOGGED 테이블
복제 안 됨. 캐시 용도면 18에서 새로 만들면 되지만 누락 인지 필요.
⑥ Replica Identity
UPDATE/DELETE 복제하려면 PK 또는 REPLICA IDENTITY 필요. 옛 테이블에 PK 없는 경우 의외로 많음.
⑦ row_security / RLS
구독자(18)의 user가 RLS 우회 권한 없으면 복제 실패. BYPASSRLS.
5. 롤백 시나리오
컷오버 후 30분 내 문제 발견 시 14로 복귀 가능하도록 역방향 복제 미리 설정:
-- 18에서
CREATE PUBLICATION rollback_pub FOR ALL TABLES;
-- 14에서
CREATE SUBSCRIPTION rollback_sub ...
이렇게 두면 컷오버 후 18에 들어온 쓰기가 14에도 반영 → 24시간 안에 안전 롤백 가능.
6. 실측 — 운영 효과
| 지표 | PG14 | PG18 |
|---|---|---|
| P50 OLTP | 4.8ms | 3.6ms |
| P99 OLTP | 62ms | 41ms |
| VACUUM ANALYZE | 27분 | 17분 |
| logical decoder lag(고부하) | ~18s | ~5s |
7. 체크리스트
- 익스텐션 양쪽 버전 호환
- cron·DDL 동결 1주 전부터
- 슬롯 사이즈 모니터링 (디스크 채우면 14 다운)
- 시퀀스 setval 스크립트 dry-run
- pgbouncer 핫리로드 사전 연습
- 역방향 복제 24시간 유지
참고
- postgresql.org/docs/18/logical-replication.html
- github.com/dimitri/pglogical-ticker — 잔여 카피 보조

댓글 0