使用 Pglogical 的 PostGres 数据库复制
I’m happy to translate the article for you, but I’ll need the actual text of the post (the paragraphs, headings, etc.) in order to do so. Could you please paste the content you’d like translated? The source line will stay unchanged, and I’ll keep all formatting, code blocks, URLs, and technical terms intact while translating the surrounding text into Simplified Chinese.
前置条件
-
Docker Engine
sudo systemctl start docker sudo systemctl enable docker # optional – start at boot -
在 Debian 上的 Docker Desktop(通过
.deb包安装)systemctl --user start docker-desktop
项目结构
//docker/
│
├── Dockerfile.pglogical
└── postgres/
└── docker-compose.yml
docker-compose.yml
在 /docker/postgres/ 目录下创建文件 docker-compose.yml:
services:
pg1:
build:
context: ..
dockerfile: Dockerfile.pglogical
container_name: pg1
command:
- postgres
- -c
- shared_preload_libraries=pglogical
- -c
- wal_level=logical
- -c
- max_replication_slots=10
- -c
- max_wal_senders=10
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: testdb
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- "5433:5432"
volumes:
- pg1_data:/var/lib/postgresql/data
networks:
- pgnet
pg2:
build:
context: ..
dockerfile: DockerFile.pglogical
container_name: pg2
command:
- postgres
- -c
- shared_preload_libraries=pglogical
- -c
- wal_level=logical
- -c
- max_replication_slots=10
- -c
- max_wal_senders=10
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: testdb
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- "5434:5432"
volumes:
- pg2_data:/var/lib/postgresql/data
networks:
- pgnet
networks:
pgnet:
driver: bridge
volumes:
pg1_data:
pg2_data:
Dockerfile.pglogical
因为基础 PostgreSQL 镜像不包含 pglogical 扩展,需要创建自定义 Dockerfile:
FROM postgres:16
RUN apt-get update \
&& apt-get install -y postgresql-18-pglogical \
&& rm -rf /var/lib/apt/lists/*
构建并启动容器
cd /docker/postgres
docker compose up -d
验证容器是否正在运行:
docker ps
您应该会看到类似如下的输出:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c61ef5d393cc postgres-pg1 "docker-entrypoint.s…" 3 days ago Up 4 minutes 0.0.0.0:5433->5432/tcp, [::]:5433->5432/tcp pg1
b055528784d5 postgres-pg2 "docker-entrypoint.s…" 3 days ago Up 4 minutes 0.0.0.0:5434->5432/tcp, [::]:5434->5432/tcp pg2
在每个容器中安装并启用 pglogical
docker exec -it pg1 psql -U postgres -d testdb
在 psql 中:
CREATE EXTENSION pglogical;
\dx -- 验证扩展已安装
你应该会看到类似以下的条目:
List of installed extensions
Name | Version | Schema | Description
----------+---------+------------+--------------------------------
pglogical| 2.4.6 | pglogical | PostgreSQL Logical Replication
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
对 pg2 容器重复相同的步骤。
将数据库注册为 pglogical 节点
在 pg1 中运行以下语句:
SELECT pglogical.create_node(
node_name := 'pg1',
dsn := 'host=pg1 port=5432 dbname=testdb user=postgres password=postgres'
);
在 pg2 中运行以下语句:
SELECT pglogical.create_node(
node_name := 'pg2',
dsn := 'host=pg2 port=5432 dbname=testdb user=postgres password=postgres'
);
在 pg1 上创建复制集
SELECT pglogical.create_replication_set(
'demo_set',
replicate_insert := true,
replicate_update := true,
replicate_delete := true,
replicate_truncate := true
);
创建表并插入基线行 (pg1)
CREATE TABLE demo_events (
id SERIAL PRIMARY KEY,
message TEXT,
created_at TIMESTAMP DEFAULT now()
);
INSERT INTO demo_events (message)
SELECT 'baseline row ' || g
FROM generate_series(1,5) g;
将表添加到复制集 (pg1)
SELECT pglogical.replication_set_add_table(
'demo_set',
'demo_events'
);
在 pg2 上创建订阅
SELECT pglogical.create_subscription(
subscription_name := 'sub_pg1',
provider_dsn := 'host=pg1 port=5432 dbname=testdb user=postgres password=postgres',
replication_sets := ARRAY['demo_set'],
synchronize_structure := true,
synchronize_data := true
);
稍等几秒,然后验证数据是否已复制:
SELECT * FROM demo_events;
您应该会看到在 pg1 上插入的五条基线记录。
测试写入方向 (pg1 → pg2)
Insert a new row on the primary (pg1):
INSERT INTO demo_events (message)
VALUES ('inserted new row');
该行会自动出现在 pg2 上。直接写入 pg2 将会触发错误,确认 pg2 是只读副本。
结论
您现在拥有两个使用 pglogical 扩展进行数据复制的 PostgreSQL 容器。对主库 (pg1) 所做的更改会自动传播到副本 (pg2),实现逻辑的、近实时的复制,无需物理流式传输。祝您使用同步的数据库愉快! 🎉