Postgres를 위한 간단한 클러스터링 및 복제 솔루션
작성자: Phil Eaton
2025년 9월 10일
우리는 이제 **EDB Postgres Distributed (PGD)**용 새로운 CLI를 제공하고 있습니다. 이 CLI를 사용하면 PGD 노드 클러스터를 아주 쉽게 만들 수 있습니다. PGD 노드는 PGD 메타데이터를 가진 Postgres 인스턴스로, 서로 연결되어 DDL(스키마)과 DML(데이터)을 논리적 복제로 동기화합니다.
PGD의 철학은 클라우드 네이티브적입니다. 어떤 노드에 문제가 생겨도 그냥 삭제한 후 다시 생성하면 놓친 데이터를 모두 자동으로 재동기화합니다.
이번 글에서는 AWS에서 세 개의 PGD 노드 클러스터를 만드는 간단하지만 수동적인 방법을 보여드리겠습니다. 이는 완전한 프로덕션 환경 설정은 아니지만 시작하는 데 도움이 될 것입니다. 이후에는 복제, 노드 삭제 및 재생성을 테스트해보겠습니다.
3개의 EC2 인스턴스 생성
먼저 Ubuntu 24.04 t3.micro EC2 인스턴스 세 개를 생성하고 각 인스턴스에 8GB 디스크를 할당합니다. 동일한 보안 그룹에 넣어주세요. 인스턴스가 생성되면 보안 그룹을 수정하여, 이 보안 그룹 내부에서 오는 모든 TCP 인바운드 연결을 허용합니다.
각 노드에서의 설정
1) 구독 토큰 설정
무료 EDB 계정을 로그인 또는 등록하고, 구독 토큰을 가져옵니다. 토큰을 환경 변수로 설정합니다.
export EDB_SUBSCRIPTION_TOKEN=whatever-it-is
2) 저장소 추가
PGD와 EDB Postgres Extended(EDB의 Postgres 배포판)용 저장소를 설정합니다.
curl -1sLf "https://downloads.enterprisedb.com/$EDB_SUBSCRIPTION_TOKEN/postgres_distributed/setup.deb.sh" | sudo -E bash
curl -1sLf "https://downloads.enterprisedb.com/$EDB_SUBSCRIPTION_TOKEN/enterprise/setup.deb.sh" | sudo -E bash
3) 패키지 설치
sudo apt-get update -y
sudo apt-get install -y edb-pgd6-expanded-pgextended17
postgres 사용자로 전환
sudo su postgres
cd ~
각 노드를 프라이빗 IP 주소로 식별합니다. 예를 들어:
export NODE0="172.31.38.10"
export NODE1="172.31.35.26"
export NODE2="172.31.43.94"
추가로 아래 변수를 지정합니다.
export PGPASSWORD="some password" # 비밀번호는 반드시 변경
export PATH=$PATH:/usr/lib/edb-pge/17/bin/
$NODE0에서의 설정
pgd node node0 setup \
--dsn "host=$NODE0 dbname=pgddb user=postgres" \
--listen-addr "$NODE0,localhost" \
--initial-node-count 3 \
--pgdata $HOME/pgddb \
--log-file $HOME/postgres.logfile \
--group-name "pgd"
클러스터 레이아웃 확인:
$ pgd --dsn "host=$NODE0 dbname=pgddb user=postgres" nodes list
Node Name | Group Name | Node Kind | Join State | Node Status
-----------+------------+-----------+------------+-------------
node0 | pgd | data | ACTIVE | Up
헬스 체크 확인:
$ pgd --dsn 'host=localhost dbname=pgddb user=postgres' cluster show
# Summary
Group Name | Parent Group | Group Type | Node Name | Node Kind
------------+--------------+------------+-----------+-----------
pgd | | global | node0 | data
# Health
Check | Status | Details
-------------------+--------+-------------------------------------------------
Connections | Ok | All BDR nodes are accessible
Raft | Ok | Raft Consensus is working correctly
Replication Slots | Ok | All PGD replication slots are working correctly
Clock Drift | Ok | Clock drift is within permissible limit
Versions | Ok | All nodes are running the same PGD version
# Clock Drift
Reference Node | Node Name | Clock Drift
----------------+-----------+-------------
출력 결과에서 연결 상태, 합의(Raft), 복제 슬롯, 클럭 드리프트, 버전 등이 정상임을 확인할 수 있습니다.
$NODE1에서의 설정
두 번째 PGD 노드를 설정합니다. ($NODE1에 postgres 사용자로 로그인되어 있는지 확인하세요.)
pgd node "node1" setup \
--dsn "host=$NODE1 dbname=pgddb user=postgres" \
--listen-addr "$NODE1,localhost" \
--pgdata $HOME/pgddb \
--log-file $HOME/postgres.logfile \
--cluster-dsn "host=$NODE0 dbname=pgddb user=postgres" \
--cluster-name "pgd"
이제 $NODE0 또는 $NODE1에서 모든 노드를 확인할 수 있습니다.
$ pgd --dsn "host=$NODE0 dbname=pgddb user=postgres" nodes list
Node Name | Group Name | Node Kind | Join State | Node Status
-----------+------------+-----------+------------+-------------
node0 | pgd | data | ACTIVE | Up
node1 | pgd | data | ACTIVE | Up
$NODE2에서의 설정
세 번째 PGD 노드를 설정합니다. ($NODE2에 postgres 사용자로 로그인되어 있는지 확인하세요.)
pgd node "node2" setup \
--dsn "host=$NODE2 dbname=pgddb user=postgres" \
--listen-addr "$NODE2,localhost" \
--pgdata $HOME/pgddb \
--log-file $HOME/postgres.logfile \
--cluster-dsn "host=$NODE0 dbname=pgddb user=postgres" \
--cluster-name "pgd"
이제 클러스터 내 어느 노드에서든 pgd nodes list
명령을 실행하면 세 개의 노드가 모두 보입니다.
$ pgd --dsn "host=$NODE0 dbname=pgddb user=postgres" nodes list
Node Name | Group Name | Node Kind | Join State | Node Status
-----------+------------+-----------+------------+-------------
node0 | pgd | data | ACTIVE | Up
node1 | pgd | data | ACTIVE | Up
node2 | pgd | data | ACTIVE | Up
DDL과 DML 복제
클러스터 구성이 끝났으니 이제 PGD를 본격적으로 사용해봅시다. $NODE0에 orders 테이블을 만들고 백만 개의 행을 삽입해보겠습니다.
DSN을 사용하기 때문에 어디에서 실행하든 실제로는 $NODE0에서 동작하게 됩니다.
$ psql "host=$NODE0 dbname=pgddb user=postgres" -c "
BEGIN;
DROP TABLE IF EXISTS orders;
CREATE TABLE orders (
customer_id INT,
order_id BIGSERIAL,
amount_pennies BIGINT,
PRIMARY KEY (customer_id, order_id)
);
INSERT INTO orders (customer_id, amount_pennies)
SELECT
random() * 9 + 1,
random() * 100000 + 1
FROM
generate_series(1, 1_000_000);
COMMIT;"
출력:
$ psql "host=$NODE0 dbname=pgddb user=postgres" -c "SELECT count(1) FROM orders"
count
---------
1000000
(1 row)
$ psql "host=$NODE1 dbname=pgddb user=postgres" -c "SELECT count(1) FROM orders"
count
---------
1000000
(1 row)
$ psql "host=$NODE2 dbname=pgddb user=postgres" -c "SELECT count(1) FROM orders"
count
---------
1000000
(1 row)
테이블이 모든 노드에 생성되었고 데이터도 복제되었습니다!
$NODE2 제거 및 재생성
가령 $NODE2에 어떤 문제가 생겼다고 해봅시다. 다시 프로비저닝해야 한다면 어떻게 할까요? 문제 없습니다! 먼저 클러스터에 이 노드를 제거하라고 알립니다.
$ pgd --dsn 'host=$NODE0 dbname=pgddb user=postgres' node node2 part
Starting a part node operation for node: node2
This may take some time, please wait...
NOTICE: node node2 has been removed from the BDR group
이제 $NODE2에서 Postgres를 중지하고 데이터 디렉토리를 삭제한 뒤, 위에서 사용했던 pgd node setup
명령을 다시 실행합니다.
$ pg_ctl -D $HOME/pgddb -l $HOME/postgres.logfile stop
waiting for server to shut down.... done
server stopped
$ rm -rf $HOME/postgres.logfile $HOME/pgddb
먼저 클러스터 상태를 조회하여 이 노드가 제거된 것을 확인합니다.
$ pgd --dsn "host=$NODE0 dbname=pgddb user=postgres" nodes list
Node Name | Group Name | Node Kind | Join State | Node Status
-----------+------------+-----------+------------+-------------
node0 | pgd | data | ACTIVE | Up
node1 | pgd | data | ACTIVE | Up
이제 $NODE2를 다시 빌드합니다.
$ pgd node "node2" setup \
--dsn "host=$NODE2 dbname=pgddb user=postgres" \
--listen-addr "$NODE2,localhost" \
--pgdata $HOME/pgddb \
--log-file $HOME/postgres.logfile \
--cluster-dsn "host=$NODE0 dbname=pgddb user=postgres" \
--cluster-name "pgd"
다시 노드 목록을 확인합니다.
$ pgd --dsn "host=$NODE0 dbname=pgddb user=postgres" nodes list
Node Name | Group Name | Node Kind | Join State | Node Status
-----------+------------+-----------+------------+-------------
node0 | pgd | data | ACTIVE | Up
node1 | pgd | data | ACTIVE | Up
node2 | pgd | data | ACTIVE | Up
복귀 완료! 재생성하기 전 클러스터에 있던 테이블과 데이터도 모두 그대로 복구되었습니다.
$ psql "host=$NODE2 dbname=pgddb user=postgres" -c "SELECT count(1) FROM orders"
count
---------
1000000
(1 row)
롤링 업그레이드 활용
참고로, 이 재생성 과정을 클러스터 롤링 업그레이드에도 사용할 수 있습니다.
- 클러스터에서 노드 하나를 제거
- 더 최신 버전의 Postgres와 PGD를 가진 새 노드를 프로비저닝
- 새 노드를 클러스터에 조인
이 과정을 모든 노드에 반복하면 클러스터 전체가 최신 버전의 Postgres와 PGD로 업그레이드됩니다.