PostgreSQL 10中的逻辑复制

PostgreSQL 10中的逻辑复制。

https://blog.2ndquadrant.com/logical-replication-postgresql-10/

分享 2017年4月28日

PostgreSQL 10即将发布它的第一个beta版本,它将包括对逻辑复制的初始支持,这主要是由我编写的,并由我的同事PeterEisentraut提交。并且在内部基于2ndQuadant在pgLogic上所做的工作(尽管用户界面有些不同)。

我想在这篇博文中分享一些基础知识的概述。

什么是逻辑复制?

让我先简单地提一下什么是逻辑复制,它有什么好处。我希望大多数人都知道PostgreSQL流主备复制,它是PostgreSQL多年来的一部分,通常用于高可用和读扩展。

那么,为什么要添加另一种复制机制,并将其称为逻辑复制呢?传统的复制工作方式是将预写日志(二进制事务日志)发送到备用服务器。这里所描述的变化是非常底层的,简单说来,它只是将文件中变更的字节一字不差的传送到备用服务器。其结果是备用服务器为主服务器的字节副本。如果你只想要一份你所有数据(和数据库)的副本,那就正好,但如果你需要对应该发送的内容和发送地点有一定的灵活性,那物理复制就不能满足需要了。这也意味着,你不能在备用上写任何东西,因为只要你在备用服务器上写任何东西,它将不再是一个确切的副本。比如,你要在备用服务器上使用临时表写操作,因此不可能在备用服务器中使用这些功能。

逻辑复制使用二进制文件中相同的信息,但将其转换回逻辑变更。这样的话,我们氷知道将包含某些数据的行被插入到特定的表中,而不是仅仅是知道应该将字节追加到文件中。这允许我们做一些有趣的事情。首先,因为我们知道哪些表发生了变化,所以我们可以根据这些变化进行筛选,这样我们就可以从数据库中复制一些表,而不是从整个实例中复制数据。这意味着的另一个区别是,下游不再只对文件应用二进制更改,而是对表应用实际更改,因此下游不再是主文件的精确二进制副本。现在我们可以对下游进行写操作,可以使用临时表,可以添加额外的索引(例如,当额外的服务器用于分析时,非常方便),甚至可以让多个上游服务器复制到单个下游并组合数据。

如何使用

逻辑复制使用发布/订阅模型,因此我们在上游(或发布者)上创建发布,在下游(或订阅者)上创建订阅。在真正做到这一点之前,我们需要稍微更改PostgreSQL的配置。PostgreSQL 10提供了新的默认设置,允许复制槽、对讲机和复制连接(所有复制的先决条件)开箱即用,因此更改并不大。首先,只需将配置参数WAL_LEVEL更改为“logical”,以便写预日志包含将二进制更改转换回逻辑更改所需的信息。

一旦基本配置完成,我们就可以开始创建发布。该命令如下所示。

CREATE PUBLICATION testpub FOR TABLE users, addresses;

以上内容将创建一个新的发布,并向其中添加用户表和地址表。还可以使用如下的命令发布数据库中的所有用户表。

CREATE PUBLICATION alltables FOR ALL TABLES;

详细信息参见CREATE PUBLICATION 文档介绍。

在创建了发布之后,其他的服务器就可以订阅他,如下所示:

CREATE SUBSCRIPTION testsub CONNECTION 'host=upstream-host dbname=users ...'
 PUBLICATION testpub;

这将创建一个新的订阅testsub,它将开始复制作为testpub发布的一部分的表。这就是基本复制工作所需要的!默认情况下,新订阅还将复制这些表中的任何现有数据。可以选择禁用它(使用WITH(NOCOPY Data)子句)。有关详细信息,请参阅创建订阅文档。请注意,该表的定义目前没有被复制,因此我们需要自己创建表,因为如果复制工作者不能在本地找到该表,则会出错。

将新表添加到发布时,订阅将不会自动发现它们,因此不会复制它们。为了复制它们,我们需要运行一个命令,更新订阅关于发布哪些表的概念:

ALTER SUBSCRIPTION testsub REFRESH PUBLICATION;

监控复制状态

现在我们已经设置好了逻辑复制,那么我们也应该看看发生了什么以及他是否正常工作。为此,有两个监视视图。其中一个是已经很熟悉的pg_stat_replication,它显示连接到当前主服务器的所有订阅者的连接信息。另一个视图是pg_stat_subscription,它显示了下游服务器上订阅的状态信息。它包含每个订阅的一个条目,以及当前正在同步的每一个表(正在复制现有数据)。

举例

这对于基本概述就足够了,现在让我们看看psql捕获的输出示例。

让我们在出版商上设置一些表格和出版物:

testdb=# CREATE TABLE customers (
 login text PRIMARY KEY,
 full_name text NOT NULL,
 registration_date timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE

testdb=# INSERT INTO customers(login, full_name) VALUES('john', 'John Doe');
INSERT 0 1

testdb=# CREATE PUBLICATION testpub FOR ALL TABLES;
CREATE PUBLICATION

设置订阅者

testdb=# CREATE TABLE customers (
 login text PRIMARY KEY,
 full_name text NOT NULL,
 registration_date timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE

testdb=# CREATE SUBSCRIPTION testsub CONNECTION 'host=localhost dbname=testdb' PUBLICATION testpub;
NOTICE:  synchronized table states
NOTICE:  created replication slot "testsub" on publisher
CREATE SUBSCRIPTION

我们可以看到,它还同步了表信息,并在发布服务器上创建了一个复制槽。

现在让我们检查一下订阅的情况。

testdb=# SELECT * FROM pg_stat_subscription;
-[ RECORD 1 ]---------+------------------------------
subid                 | 16403
subname               | testsub
pid                   | 13109
relid                 | [NULL]
received_lsn          | 0/15F1A10
last_msg_send_time    | 2017-04-28 10:38:17.862848+02
last_msg_receipt_time | 2017-04-28 10:38:17.864402+02
latest_end_lsn        | 0/15F1A10
latest_end_time       | 2017-04-28 10:38:17.862848+02

并验证是否复制了现有行。

testdb=# SELECT * FROM customers;
-[ RECORD 1 ]-----+------------------------------
login             | john
full_name         | John Doe
registration_date | 2017-04-28 10:36:00.112817+02

一切如愿。回到提供者,我们也可以检查复制状态,就像正常的备用状态一样。

testdb=# SELECT application_name, backend_start, state, sent_location, write_location, flush_location, sync_state FROM pg_stat_replication ;
-[ RECORD 1 ]----+------------------------------
application_name | testsub
backend_start    | 2017-04-28 10:38:16.852043+02
state            | streaming
sent_location    | 0/15F1A10
write_location   | 0/15F1A10
flush_location   | 0/15F1A10
sync_state       | async

请注意,此处显示的application_name与我们创建的订阅的名称相同。

好的,我们再插入一行并检查它是否被复制。

testdb=# INSERT INTO customers(login, full_name) VALUES('jane', 'Jane Doe');
INSERT 0 1

在订阅者上,我们可以再次看到数据:

testdb=# SELECT * FROM customers;
 login | full_name |       registration_date
-------+-----------+-------------------------------
 john  | John Doe  | 2017-04-28 10:36:00.112817+02
 jane  | Jane Doe  | 2017-04-28 10:40:53.332686+02
(2 rows)

总结

将逻辑复制放入PostgreSQL是一项艰巨的任务,我很高兴我们能够将一些东西放入PostgreSQL 10中,这已经非常有用了。它并不具备所有的pgLogic特性,但是它仍然是提供这个功能强大的基本版本的一个重要步骤。它还为PostgreSQL中的其他功能打开了底层技术的其他可能用途。

我们将在以后的博客文章中更深入地研究逻辑复制的某些方面--所以一定要关注我们的社交渠道,不要错过更新!

如果希望能从pg9.6通过逻辑复制升级到pg10,只能使用9.6的pglogical插件,pg10的逻辑复制只支持从pg10升级到将来的pg11。

pg10的逻辑复制只支持 正常 的表,不支持视图,物化视图,分区表的主表这些对象。也不支持多主复制。

问题解答

可以设置双向复制不?

可以。 但是,如果您在另一个节点上有未完成的提交而对新模式没有意义的情况下进行任何架构更改,它就会崩溃。此外,如果您进行了任何更改,造成了冲突的行,您将不得不手动修复它们,因为没有自动解决冲突。https://www.postgresql.org/docs/10/静态/逻辑-复制-冲突.html。还有更多的陷阱。

简而言之,不要用双向复制。我们开发BDR是有原因的,还有很多事情要做,而不是两个DBS对着对方。

是否有计划实现多主,只需要将订阅指向对方就可以?

这并不是那么简单,因为当多个节点上的行发生更改时,围绕冲突的问题、模式更改的问题等等。 BDR很可能成为所采取的方向的基本模式。

问: 您说订阅服务器没有接收添加到发布服务器的新表,但是表更改(即:添加/删除列、添加/删除/更改索引)是否在现有表上传递? 删除源表时会发生什么情况?它是删除订阅服务器表还是停止发送更新?

答: 内置逻辑复制中没有DDL复制.。因此,表更改不会自动传播。 如果删除源表,它将停止发送更新。

这有外部API吗?复制主db的子集将使许多服务受益,但示例仅适用于另一个PG db。

答: 还没。您可以使用‘pgputplugin’,但是您必须编写代码来使用Walsender发送方协议流和输出plugin的二进制协议。或者在SQL中使用它,但是您仍然需要使用输出插件协议。 查看pgLogic,它有一个JSON输出模式。或wal2json,或许多其他工具。

在PostgreSQL黑客名单上,人们对此非常感兴趣。参与进来。贡献、提交补丁、测试等。

问: 那序列呢? 是否“为所有表创建发布所有表;”也包括它们?

答: 序列的支持是添加。 有关详细信息,请参见PostgreSQL 10中的文档。

pglogical和pg10的逻辑复制

pglogical插件和pg10的逻辑复制虽然看起来一样,但其实是两个不同的东西。

pg10逻辑复制和Slony差别

那么,你觉得这比Slony怎么样?既然它是以Wal日志为基础的,我们能假设它在高容量系统上会有更少的滞后吗?这会阻止写入订阅服务器表吗?是否有一种简单的原子方法来更改发布者,即所谓的故障转移?

答: 它不具有太大的写放大效应,特别是对小的交易,它应该快得多。 它不阻止对订阅服务器表的写入,但您可以使用常规PostgreSQL权限进行写入。取消他们的写权限。 目前还没有故障转移支持。希望我们能在pg 11或pg 12中解决这个问题。

转载于:https://my.oschina.net/lvhongqing/blog/1574869

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值