PostgreSQL 논리적 복제(Logical Replication)는 WAL(Write-Ahead Log) 기반으로 행 수준 변경을 다른 PostgreSQL 인스턴스로 복제하는 기능이다. 물리적 복제와 달리 선택적 테이블/스키마 복제와 버전 간 복제가 가능하다.
논리적 복제 vs 물리적 복제
| 항목 | 물리적 복제 | 논리적 복제 |
|---|
| 복제 단위 | 블록 레벨 | 행 레벨 |
| 선택적 복제 | 전체 클러스터 | 테이블/컬럼 선택 |
| 버전 호환 | 동일 메이저 버전 | 다른 버전 가능 |
| 복제본 읽기 | 읽기 전용 | 읽기/쓰기 모두 |
| 충돌 처리 | 없음 | 처리 필요 |
| 용도 | HA, 읽기 확장 | 마이그레이션, 필터링 |
설정 방법
sql
-- === 발행자(Publisher) 설정 ===
-- postgresql.conf
-- wal_level = logical
-- max_replication_slots = 4
-- max_wal_senders = 4
-- 발행 생성
CREATE PUBLICATION my_pub
FOR TABLE articles, categories -- 특정 테이블만
WITH (publish = 'insert, update, delete');
-- 또는 전체 DB
CREATE PUBLICATION all_tables FOR ALL TABLES;
-- === 구독자(Subscriber) 설정 ===
-- 구독 생성 (다른 PostgreSQL 서버에서)
CREATE SUBSCRIPTION my_sub
CONNECTION 'host=publisher-host dbname=blog user=replicator password=secret'
PUBLICATION my_pub;
-- 구독 상태 확인
SELECT subname, subenabled, subpublications
FROM pg_subscription;
-- 복제 슬롯 확인 (발행자)
SELECT slot_name, plugin, active, restart_lsn
FROM pg_replication_slots;
CDC (Change Data Capture) with pgoutput
python
# psycopg2 + pgoutput 디코딩 플러그인
import psycopg2
from psycopg2.extras import LogicalReplicationConnection
conn = psycopg2.connect(
"host=localhost dbname=blog user=replicator",
connection_factory=LogicalReplicationConnection
)
cur = conn.cursor()
# 복제 슬롯 생성 (없으면)
cur.create_replication_slot('cdc_slot', output_plugin='pgoutput')
# 복제 스트림 시작
cur.start_replication(
slot_name='cdc_slot',
decode=True,
options={'proto_version': '1', 'publication_names': 'my_pub'}
)
class CDC:
def __call__(self, msg):
# 변경 이벤트 처리
payload = msg.payload
print(f"Change: {payload}")
msg.cursor.send_feedback(flush_lsn=msg.data_start)
cur.consume_stream(CDC())
관련 문서