PostgreSQL 읽기 복제본, WAL, 복제 슬롯, 퍼블리케이션에 대하여
PostgreSQL에서 대규모 데이터베이스 환경을 운영할 때 자주 등장하는 개념으로는 먼저 Write-Ahead Log, 흔히 줄여서 WAL이라고 부르는 로그 구조가 있다. PostgreSQL은 모든 변경(INSERT, UPDATE, DELETE)을 WAL에 기록하여 트랜잭션의 무결성을 보장하고 장애 발생 시 복구를 가능하게 만든다.
PostgreSQL은 어떤 데이터를 수정하기 전, 변경 내용을 먼저 WAL에 기록한다. 이 로그는 트랜잭션 단위로 데이터베이스 조작 이력을 남기고, 추후 장애가 발생했을 때 해당 내용을 재적용하거나 롤백하는 용도로도 사용된다. 이처럼 데이터를 실제로 수정하기 전에 WAL을 작성함으로써 데이터 무결성과 복구 가능성을 확보할 수 있다. WAL은 또한 여러 형태의 복제 방식에서 중요한 역할을 한다. 마스터 서버에서 WAL을 생성하면, 이 로그를 다른 서버나 시스템으로 전달해 동기화할 수 있는데, 이때 읽기 전용 복제본이나 논리적 복제 슬롯이 등장한다.
논리적 복제 슬롯(Replication Slot)은 PostgreSQL에서 WAL 로그를 논리적 형태로 추출하고, 이를 외부 Subscriber가 구독할 수 있도록 유지하는 구조물이다. 단순히 테이블 전체를 복제하는 것이 아니라, 테이블 레벨의 변경 사항을 추적해 전달하기 위해서 필요한 개념이다. 논리적 디코딩(Logical Decoding)을 거친 WAL 이벤트를 누구나 손쉽게 읽을 수 있는 형태로 내보낼 수 있게 해주는데, 슬롯은 이 과정에서 이벤트를 안전하게 보관해두고 소비자가 가져갈 때까지 삭제되지 않도록 관리한다. 중요한 점은 논리적 복제 슬롯이 마스터 서버의 WAL을 직접 참조한다는 사실이다. 즉, 실제로 WAL을 생성하는 쪽은 마스터이며, 슬롯 또한 마스터 DB에 위치해야만 한다. 읽기 전용 복제본에는 WAL이 기본적으로 생기지 않고, 슬레이브 역할만 하기 때문에 복제 슬롯을 만드는 것이 불가능하다. 또한 슬롯 접근 권한을 부여하거나 소유자를 바꾸는 행위도 표준 PostgreSQL에서는 허용되지 않으므로, 일반적으로 슬롯을 만든 유저 또는 슈퍼유저 권한이 있는 계정만 해당 슬롯을 사용할 수 있다.
“SELECT pg_create_logical_replication_slot(‘live_slot’, ‘pgoutput’)”라는 쿼리를 사용하면 live_slot이라는 이름의 논리적 복제 슬롯을 pgoutput 플러그인을 통해 생성하게 되고, 이 슬롯이 만들어진 데이터베이스의 WAL을 논리적으로 해석하여 외부로 제공한다.
같은 맥락에서 “CREATE PUBLICATION live_publication FOR ALL TABLES”와 같은 쿼리는 해당 데이터베이스 내 존재하는 모든 테이블을 복제 대상으로 지정하는 퍼블리케이션을 만드는 명령이다. 이러한 퍼블리케이션과 복제 슬롯을 이용해 다른 시스템이나 서비스에서 PostgreSQL 변경 데이터를 스트리밍 형태로 가져가 실시간 분석 또는 데이터 파이프라인 구축을 할 수 있다.
여기서 주의할 점은 리드 레플리카(Read Replica)에서 이러한 슬롯이나 퍼블리케이션을 생성할 수 없다는 것이다. 보통 리드 레플리카는 읽기 전용으로 동작하며, 마스터(또는 프라이머리) 데이터베이스에서 발생한 WAL을 받아 그대로 반영하기만 한다. 실제로 WAL 원본을 만들거나 논리적 복제를 제어하는 작업은 마스터에서 이루어진다. 따라서 “SELECT pg_create_logical_replication_slot(…)”와 같은 쿼리를 리드 레플리카에서 실행하면 권한 오류나 지원되지 않는 기능이라는 메시지가 뜰 가능성이 높다.
퍼블리케이션(Publication)은 PostgreSQL 논리적 복제를 구성할 때 “어떤 테이블을 대상으로 복제할 것인가”를 정의해 두는 객체다. 퍼블리케이션을 생성하며 특정 테이블 혹은 스키마 전부를 등록하고, 이후에 구독자(Subscriber)가 어떤 퍼블리케이션을 구독할지 결정한다. 구독자는 퍼블리케이션 이름, 슬롯 이름, 데이터베이스 연결 정보 등을 바탕으로 데이터 변경 사항을 받아간다. 퍼블리케이션을 만드는 위치는 마스터(DB)이며, 구독을 생성하는 곳은 데이터가 도착하기 원하는 쪽(다른 PostgreSQL DB나 외부 도구)이다. 복제 슬롯이 없으면 퍼블리케이션만 만들어도 로그가 저장되지 않기 때문에, 대부분 논리적 복제를 쓸 때는 퍼블리케이션과 슬롯이 함께 사용된다.
당연히 “CREATE PUBLICATION” 명령도 마찬가지로 리드 레플리카에서 허용되지 않는 경우가 대부분이다. 결론적으로 논리적 복제를 통해 변동 사항을 추출하려면 반드시 마스터 데이터베이스에서 슬롯과 퍼블리케이션을 생성해야 하며, 이 작업에 필요한 계정은 보통 “WITH REPLICATION” 권한이나 슈퍼유저에 준하는 권한이 있어야 한다. 만약 Cloud SQL for PostgreSQL 같은 관리형 서비스에서라면 “cloudsqlsuperuser” 역할과 “WITH REPLICATION” 옵션이 동시에 필요한 경우가 많다.
실제로 논리적 복제 슬롯이 제대로 생성되었는지 확인하려면 “SELECT * FROM pg_logical_slot_peek_changes(‘live_slot’, NULL, NULL) LIMIT 1” 같은 쿼리를 통해 이벤트 스트림을 미리 살펴볼 수 있다. 만약 이 과정에서 권한이 없다는 오류가 나오거나 “슬롯이 이 데이터베이스에 없다”라는 에러 메시지가 뜬다면, 슬롯을 만든 계정과 실제로 테스트를 수행하는 계정이 일치하는지, 슬롯이 만들어진 데이터베이스 이름이 Datastream이나 다른 애플리케이션이 접속하는 DB와 동일한지, 혹은 WAL 레벨과 cloudsql.logical_decoding 파라미터 등 복제 관련 설정이 올바르게 되어 있는지를 점검해야 한다.
클라우드 환경에서 PostgreSQL 논리적 복제와 유사한 개념으로, Google Cloud Datastream처럼 외부 시스템으로 변경 사항을 전송해주는 CDC(Change Data Capture) 서비스가 등장한다. Datastream은 PostgreSQL의 퍼블리케이션과 슬롯을 통해 변경된 데이터를 읽고, 이를 BigQuery나 다른 대상에 실시간으로 적재할 수 있게 해준다. BigQuery는 페타바이트 급 분석을 수행하는 강력한 서버리스 데이터 웨어하우스로, 실시간에 가까운 로그를 받아 거대한 규모의 데이터를 집계 및 분석할 수 있다. 이를 위해서는 PostgreSQL 측에서 논리적 복제를 올바르게 설정해 두고, Datastream이 접근할 수 있는 슬롯과 퍼블리케이션을 정확히 구성해야 한다. 읽기 복제본에서는 앞서 언급했듯 퍼블리케이션이나 슬롯을 만들 수 없으므로 반드시 마스터 혹은 프라이머리 인스턴스에서 해당 작업을 진행한다.
결국 PostgreSQL에서 논리적 복제를 통해 바깥으로 데이터를 내보내려면 꼭 마스터 DB에 퍼블리케이션과 슬롯을 만들고, 적절한 권한(복제 권한과 해당 테이블에 대한 SELECT 권한)을 가진 계정이 이 슬롯을 사용해 로그를 읽어 가야 한다. BigQuery와의 연동은 대개 CDC 파이프라인을 통해 이뤄지는데, Google Datastream 또는 별도의 오픈소스 도구로 PostgreSQL 변경 데이터를 수집해 BigQuery로 실어나르고, BigQuery에서 이를 기반으로 대용량 분석을 수행한다. 이렇게 하면 애플리케이션 DB의 부하와 상관없이 거대 규모의 쿼리를 돌릴 수 있고, 비용도 스캔된 데이터 양이나 스토리지 사용량에 따라 유연하게 계산되는 장점이 있다.
따라서 이 모든 과정을 위해서는 앞서 언급했듯이 마스터 DB에서 필요한 퍼블리케이션과 슬롯을 생성하고, Datastream에서 접속할 계정에 올바른 권한을 주어야 한다. 예시로 보면 “CREATE USER replication_user WITH REPLICATION IN ROLE cloudsqlsuperuser LOGIN PASSWORD ‘…’”
같은 쿼리로 전용 계정을 만들 수 있고, 이어서 “GRANT SELECT ON ALL TABLES IN SCHEMA public TO ereplication_user”와 같은 식으로 실제 테이블 데이터에 대한 접근 권한을 부여해야 한다. 그 뒤에 replication_user로 접속하여 “CREATE PUBLICATION live_publication FOR ALL TABLES”
와 “SELECT pg_create_logical_replication_slot(‘live_slot’, ‘pgoutput’)”
를 실행하면 마스터 DB에서 논리적 복제를 위한 준비가 완료된다.
마무리 점검을 위해 다시 SELECT * FROM pg_logical_slot_peek_changes(‘live_slot’, NULL, NULL) LIMIT 1
쿼리를 수행해 정상적인 결과를 확인하면, Datastream이나 외부 CDC 도구가 해당 슬롯을 구독(subscribe)하여 변경 데이터를 읽을 수 있게 된다.
결국 마스터 서버에서 WAL을 논리적으로 디코딩하는 퍼블리케이션과 슬롯을 생성하고, 그 정보를 Google BigQuery와 같은 분석 환경이나 다른 외부 시스템에서 읽어가는 구조가 PostgreSQL의 논리적 복제가 하는 일의 핵심이다. 리드 레플리카는 WAL 생성의 주체가 아니므로 여기에선 위와 같은 작업이 불가능하고, 당연히 실제 논리적 복제 구성도 마스터를 중심으로 이뤄져야 한다. 이러한 점을 염두에 두고 구성을 올바르게 마치면, PostgreSQL 데이터를 대용량으로 운영하면서도 실시간 분석 요구를 만족하는 강력한 아키텍처를 완성할 수 있다.