暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

PostgreSQL中使用 pgcopydb 更快的逻辑备份/恢复

原创 黎青峰 2022-10-14
2016

毫无疑问,pg_dump / pg_restore是在 PostgreSQL 中执行逻辑备份和恢复的绝佳工具。我们已经在这里详细解释了 pg_dump/pg_restore 。

pgcopydb 是一个开源工具,可以在两个 PostgreSQL 服务器之间自动执行 pg_dump 和 pg_restore。它是 pg_dump 和 pg_restore 的包装器,以简化流程并提供更多功能。在这篇博文中,我们将详细介绍pgcopydb

为什么我们需要考虑 pgcopydb?

pgcopydb 有助于实现直接使用 pg_dump/pg_restore 无法实现的两个重要的事情。

1.没有中间文件

为了使用 pg_dump/pg_restore 实现更快的转储和恢复,我们需要使用并行性。为了实现这一点,两者都必须使用 –jobs 参数。每当我们使用 –jobs 参数来支持并行性时,它都需要写入中间文件。

例如,我们计划将 1 TB 的数据从源复制到目标,我们需要先将转储文件存储在本地。这意味着我们在服务器上需要额外的磁盘空间来放置转储。所需的磁盘空间取决于数据的大小。

通过使用 pgcopydb,我们不需要任何额外的磁盘空间来放置转储,因为该工具将完全绕过表数据的中间文件并且它支持并行性。

这是通过在整个操作期间连接到源数据库来实现的,而对于 pg_restore,不需要总是连接到源数据库,因为它从磁盘中间文件恢复数据。

2.同时创建所有索引

pg_dump/pg_restore 直接使用 ALTER TABLE 命令来构建索引和约束。但是 ALTER TABLE .. ADD CONSTRAINT 命令需要 ACCESS EXCLUSIVE 锁来防止任何并发。

在 pgcopydb 中,它首先执行 CREATE UNIQUE INDEX 语句。完成后,它只需使用ALTER TABLE .. ADD CONSTRAINT .. PRIMARY KEY USING INDEX 添加约束。这是有助于同时在表中构建所有索引的方式。

安装

在 Ubuntu 中安装非常简单。以下是步骤

1. 导入仓库密钥

1

2

sudo apt install curl ca-certificates gnupg

curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null

2. 创建 /etc/apt/sources.list.d/pgdg.list。

1

sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'

3.安装pgcopydb

1

2

sudo apt update

sudo apt-get install pgcopydb

对于其他发行版,请参阅此处

以下是依赖项

  1. Source 和 Destination 应该可以从运行 pgcopydb 的主机访问。此外,在成功迁移的整个过程中,源和目标都应该可用。
  2. 尽管 pgcopydb 不需要任何存储来在本地存储数据文件,但它在运行 pgcopydb 的服务器上需要非常少量的存储。这是保留模式备份和一些临时文件以保持进度所必需的。这将是非常小的大小,因为它只包含模式对象的结构。默认情况下,它将使用路径 /tmp/pgcopydb。如果需要使用其他路径,我们可以使用 –dir 选项。
  3. pgcopydb 依赖于运行 pgcopydb 的服务器中的 pg_dump 和 pg_restore 工具。pg_dump 和 pg_restore 的工具版本应该与目标数据库的 PostgreSQL 版本相匹配。

工作流程

以下工作流程解释了如何在两个不同的 PostgreSQL 服务器之间使用 pgcopydb 进行数据库复制。

  1. pgcopydb 首先使用来自源服务器的自定义格式(不是纯文本)的 pg_dump 生成仅模式备份。它将在两个文件中 a) 前数据部分 b) 后数据部分
  2. pre-data 节文件将使用 pg_restore 命令在目标服务器中恢复。它在目标服务器中创建所有 PostgreSQL 对象。
  3. pgcopydb 从源服务器获取所有表的列表,并在专用子进程中为每个表执行从源到目标的复制过程。它将对所有表执行,直到所有数据都被复制过来。
  4. 一个辅助进程与第 3 点中提到的主复制进程同时启动。该进程负责将所有大对象从源复制到目标。
  5. 在第 3 点提到的每个复制表子过程中,只要复制表数据,pgcopydb 就会获取索引列表并在目标服务器中并行创建它们。
  6. 正如我们在上一节中讨论的那样,索引创建将并行执行。
  7. 一旦创建了数据和索引,就会对每个目标表执行 Vacuum 分析。
  8. 现在,pgcopydb 获取序列列表并在目标服务器中相应地更新值。
  9. 最后,将在目标数据库中创建包含外键约束的 post-data 部分。
  10. 最重要的是,成功完成使数据库从源恢复到目标成功。

演示

在这个演示中,让我们看看如何执行从源到目标的完整数据库复制,以及它与 pg_dump/pg_restore 的比较。

服务器类型主机 IP
资源192.168.33.11
目的地192.168.33.12
pgcopydb192.168.33.13

在单独的服务器中运行 pgcopydb 不是强制性的。它也可以安装在源服务器或目标服务器中。

现在将完整的数据库演示从源复制到目标。

在 pgcopydb 服务器中设置连接字符串

1

2

export PGCOPYDB_SOURCE_PGURI="port=5432 host=192.168.33.11 dbname=demo user=backup password=K5cq5M8yZtpV"

export PGCOPYDB_TARGET_PGURI="port=5432 host=192.168.33.12 dbname=demo user=backup password=RK5cq5M8ZtpV"

启动 pgcopydb

pgcopydb copy-db --table-jobs 16 --index-jobs 16

 

 

12:17:10 3971226 INFO  Running pgcopydb version 0.6-1.pgdg20.04+1 from "/usr/bin/pgcopydb"

12:17:10 3971226 INFO  [SOURCE] Copying database from "postgres://backup@192.168.33.11:5432/demo?password=****"

12:17:10 3971226 INFO  [TARGET] Copying database into "postgres://backup@192.168.33.12:5432/demo?password=****"

12:17:10 3971226 INFO  Using work dir "/tmp/pgcopydb"

12:17:10 3971226 INFO  STEP 1: dump the source database schema (pre/post data)

12:17:10 3971226 INFO  Exported snapshot "00000004-00000F28-1" from the source database

12:17:10 3971226 INFO   /usr/bin/pg_dump -Fc --snapshot 00000004-00000F28-1 --section pre-data --file /tmp/pgcopydb/schema/pre.dump 'postgres://backup@192.168.33.11:5432/demo?'

12:17:10 3971226 INFO   /usr/bin/pg_dump -Fc --snapshot 00000004-00000F28-1 --section post-data --file /tmp/pgcopydb/schema/post.dump 'postgres://backup@192.168.33.11:5432/demo?'

12:17:11 3971226 INFO  STEP 2: restore the pre-data section to the target database

12:17:11 3971226 INFO   /usr/bin/pg_restore --dbname 'postgres://backup@192.168.33.12:5432/demo?' /tmp/pgcopydb/schema/pre.dump

12:17:11 3971226 INFO  STEP 3: copy data from source to target in sub-processes

12:17:11 3971226 INFO  STEP 4: create indexes and constraints in parallel

12:17:11 3971226 INFO  STEP 5: vacuum analyze each table

12:17:11 3971226 INFO  Listing ordinary tables in source database

12:17:11 3971226 INFO  Fetched information for 10 tables, with an estimated total of 100000108 tuples and 20 GB

12:17:11 3971226 INFO  Now starting 10 processes

12:17:11 3971226 INFO  Reset sequences values on the target database

12:17:11 3971226 INFO  Listing sequences in source database

12:17:11 3971226 INFO  Fetched information for 10 sequences

12:17:11 3971243 INFO  COPY "public"."sbtest1";

12:17:11 3971244 INFO  COPY "public"."sbtest10";

12:17:11 3971247 INFO  COPY "public"."sbtest2";

12:17:11 3971245 INFO  COPY "public"."sbtest3";

12:17:11 3971249 INFO  COPY "public"."sbtest4";

12:17:11 3971251 INFO  COPY "public"."sbtest5";

12:17:11 3971253 INFO  COPY "public"."sbtest6";

12:17:11 3971256 INFO  COPY "public"."sbtest7";

12:17:11 3971255 INFO  COPY "public"."sbtest8";

12:17:11 3971257 INFO  COPY "public"."sbtest9";

12:17:11 3971242 INFO  Copying large objects

12:20:23 3971244 INFO  Creating 2 indexes for table "public"."sbtest10"

12:20:23 3972757 INFO  VACUUM ANALYZE "public"."sbtest10";

12:20:23 3972758 INFO  CREATE UNIQUE INDEX sbtest10_pkey ON public.sbtest10 USING btree (id);

12:20:23 3972759 INFO  CREATE INDEX k_10 ON public.sbtest10 USING btree (k);

12:20:23 3971243 INFO  Creating 2 indexes for table "public"."sbtest1"

12:20:23 3972764 INFO  VACUUM ANALYZE "public"."sbtest1";

12:20:23 3972765 INFO  CREATE UNIQUE INDEX sbtest1_pkey ON public.sbtest1 USING btree (id);

12:20:23 3972766 INFO  CREATE INDEX k_1 ON public.sbtest1 USING btree (k);

12:20:24 3971249 INFO  Creating 2 indexes for table "public"."sbtest4"

12:20:24 3972789 INFO  VACUUM ANALYZE "public"."sbtest4";

12:20:24 3972790 INFO  CREATE UNIQUE INDEX sbtest4_pkey ON public.sbtest4 USING btree (id);

12:20:24 3972791 INFO  CREATE INDEX k_4 ON public.sbtest4 USING btree (k);

12:20:24 3971251 INFO  Creating 2 indexes for table "public"."sbtest5"

12:20:24 3972808 INFO  VACUUM ANALYZE "public"."sbtest5";

12:20:24 3972809 INFO  CREATE UNIQUE INDEX sbtest5_pkey ON public.sbtest5 USING btree (id);

12:20:24 3972810 INFO  CREATE INDEX k_5 ON public.sbtest5 USING btree (k);

12:20:25 3971245 INFO  Creating 2 indexes for table "public"."sbtest3"

12:20:25 3972815 INFO  VACUUM ANALYZE "public"."sbtest3";

12:20:25 3972816 INFO  CREATE UNIQUE INDEX sbtest3_pkey ON public.sbtest3 USING btree (id);

12:20:25 3972817 INFO  CREATE INDEX k_3 ON public.sbtest3 USING btree (k);

12:20:25 3971253 INFO  Creating 2 indexes for table "public"."sbtest6"

12:20:25 3972822 INFO  VACUUM ANALYZE "public"."sbtest6";

12:20:25 3972823 INFO  CREATE UNIQUE INDEX sbtest6_pkey ON public.sbtest6 USING btree (id);

12:20:25 3972824 INFO  CREATE INDEX k_6 ON public.sbtest6 USING btree (k);

12:20:25 3971257 INFO  Creating 2 indexes for table "public"."sbtest9"

总时间总结

      OID | Schema |     Name | copy duration | indexes | create index duration

----------+--------+----------+---------------+---------+----------------------

392532910 | public |  sbtest1 |         3m12s |       4 |                 3m26s

392532903 | public | sbtest10 |         3m11s |       4 |                 3m11s

392532907 | public |  sbtest2 |         3m14s |       4 |                 5m10s

392532912 | public |  sbtest3 |         3m13s |       4 |                 4m28s

392532894 | public |  sbtest4 |         3m13s |       4 |                 3m14s

392532895 | public |  sbtest5 |         3m13s |       4 |                 5m54s

392532906 | public |  sbtest6 |         3m14s |       4 |                 5m55s

392532913 | public |  sbtest7 |         3m14s |       4 |                 5m59s

392532911 | public |  sbtest8 |         3m14s |       4 |                 5m04s

392532896 | public |  sbtest9 |         3m14s |       4 |                 3m17s

 

 

                                          Step   Connection    Duration   Concurrency

 ---------------------------------------------   ----------  ----------  ------------

                                   Dump Schema       source       482ms             1

                                Prepare Schema       target       110ms             1

 COPY, INDEX, CONSTRAINTS, VACUUM (wall clock)         both       6m16s       10 + 16

                             COPY (cumulative)         both      32m17s            10

                    Large Objects (cumulative)         both         7ms             1

        CREATE INDEX, CONSTRAINTS (cumulative)       target      45m42s            16

                               Finalize Schema       target        63ms             1

 ---------------------------------------------   ----------  ----------  ------------

                     Total Wall Clock Duration         both       6m17s       10 + 16

 ---------------------------------------------   ----------  ----------  ------------

将 25GB 的数据库从一台服务器复制到另一台服务器总共花费了 6 分 17 秒。让我们直接尝试使用 pg_dump/pg_restore 进行相同的数据复制。

time pg_dump -h192.168.33.11 -Ubackup --port=5432 -Fd  demo -j 16 -f backup

 

real    2m34.974s

user    24m38.031s

sys     0m24.372s

 

time pg_restore -h192.168.33.12  -Ubackup  --port=5432  -d demo  -j 16 backup/

 

real    6m5.533s

user    1m58.733s

sys     0m8.671s

备份总共耗时 2 分 34 秒,还原耗时 6 分 5 秒,清理耗时 22 秒。即)9分钟。两个测试都使用了 16 个并行线程。

方法所用时间(秒)
pgcopydb377
pgdump/pgrestore519

根据统计数据,我们可以看到 pgcopydb 在 PostgreSQL 中执行逻辑备份和恢复的效率如何。到目前为止,我们只讨论了如何执行从源到目标的完整数据库复制。pgcopydb 还支持其最新版本的过滤(复制特定对象)。在我们的下一篇博客文章中,我们将了解如何在 pgcopydb 中使用过滤。此功能对于日常数据库操作也非常有用。


原文标题:Faster Logical Backup/Restore using pgcopydb – PostgreSQL

原文作者:Aakash Muthuramalingam

原文地址:https://mydbops.wordpress.com/2022/05/24/faster-logical-backup-restore-using-pgcopydb-postgresql/

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论