数据库版本:

一、启动两阶段提交
1发布方
- 创建表和发布。
postgres=# CREATE TABLE test (col1 INT, col2 TEXT, PRIMARY KEY(col1));
CREATE TABLE
postgres=# CREATE PUBLICATION pub FOR TABLE test;

2订阅方
- 创建同一个表,并创建一个启用 two_phase 模式的订阅。
- 检查subtwophasestate列以验证它是否启用了two_phase(如果值为e,则开启了)。
postgres=# CREATE TABLE test (col1 INT, col2 TEXT, PRIMARY KEY(col1));
CREATE TABLE
postgres=# CREATE SUBSCRIPTION sub CONNECTION 'dbname=postgres host=172.20.10.6 port=6000 user=ysla password=1qaz!QAZ' PUBLICATION pub WITH (two_phase = on);
NOTICE: created replication slot "sub" on publisher
CREATE SUBSCRIPTION
postgres=# SELECT subtwophasestate FROM pg_subscription;
subtwophasestate
------------------
e
(1 row)


相应日志为
发布节点

订阅节点

3发布方
- 开始交易。
- 插入一些数据。
- 准备事务并检查 GID。
postgres=# BEGIN;
BEGIN
postgres=*# INSERT INTO test VALUES (7,'aa');
INSERT 0 1
postgres=*# PREPARE TRANSACTION 't1';
PREPARE TRANSACTION
操作的时候由于疏忽,没启动prepare transaction ,这点需要注意,要启动prepare transaction,需要到postgresql.conf配置文件中,将参数max_prepare_transactions设置为非零的值,然后重启数据库服务即可 。

参数修改后,正确的如下

4订阅方
- 检查订阅端并查看生成的准备好的事务 GID 也在那里复制。
postgres=# SELECT * FROM pg_prepared_xacts;

此时我们检查订阅节点的pg_twophase目录,该目录包含预备事务的状态文件


对于这个二进制文件,我们可以用hexdump查看内容,例如:

5发布方
- 提交准备好的事务。
- 观察准备好的事务 GID 现在已经消失(它已提交)。
- 选择插入的数据。
postgres=# COMMIT PREPARED 't1';
COMMIT PREPARED
postgres=# SELECT * FROM pg_prepared_xacts;
transaction | gid | prepared | owner | database
------------+-----+----------+-------+----------
(0 rows)
postgres=# SELECT * FROM test;
a | b
---+----
7 | aa
(1 row)

6订阅方
- 订阅方生成的 GID 也消失了(已提交)。
- 选择显示已复制发布的数据。
postgres=# SELECT * FROM pg_prepared_xacts;
transaction | gid | prepared | owner | database
------------+-----+----------+-------+----------
(0 rows)
postgres=# SELECT * from test;
a | b
---+----
7 | aa
(1 row)

订阅节点的pg_twophase目录里的对应事务状态的文件已经不存在了

二、不启动两阶段提交
1发布方
- 创建表和发布。
postgres=# CREATE TABLE test2 (col1 INT, col2 TEXT, PRIMARY KEY(col1));
CREATE TABLE
postgres=# CREATE PUBLICATION pub FOR TABLE test2;

2订阅方
- 创建同一个表,并创建一个启用 two_phase 模式的订阅。
- 检查subtwophasestate列以验证它是否启用了two_phase(如果值为e,则开启了)。
postgres=# CREATE TABLE test2 (col1 INT, col2 TEXT, PRIMARY KEY(col1));
CREATE TABLE
postgres=# CREATE SUBSCRIPTION sub2 CONNECTION 'dbname=postgres host=172.20.10.6 port=6000 user=ysla password=1qaz!QAZ' PUBLICATION pub2 WITH (two_phase = off);
NOTICE: created replication slot "sub2" on publisher
CREATE SUBSCRIPTION
postgres=# SELECT subname,subtwophasestate FROM pg_subscription;
subname | subtwophasestate
---------+------------------
sub | e
sub2 | d
(2 rows)

3发布方
- 开始交易。
- 插入一些数据。
- 准备事务并检查 GID。
postgres=# BEGIN;
BEGIN
postgres=*# INSERT INTO test2 VALUES (22,'aa');
INSERT 0 1
postgres=*# PREPARE TRANSACTION 't2';
PREPARE TRANSACTION
postgres=# SELECT * FROM pg_prepared_xacts;
transaction | gid | prepared | owner | database
-------------+-----+-------------------------------+----------+----------
749 | t2 | 2022-04-24 19:12:27.372256+08 | postgres | postgres
(1 row)

4订阅方
- 检查订户端并查看生成的准备好的事务 GID 也在那里复制。
postgres=# SELECT * FROM pg_prepared_xacts;
transaction | gid | prepared | owner | database
-------------+------------------+-------------------------------+----------+----------
1951 | pg_gid_24607_749 | 2022-04-24 19:12:27.602742+08 | postgres | postgres
(1 row)
postgres=# select * from test2;
col1 | col2
------+------
(0 rows)

此时在订阅节点的pg_twophase目录下,也传输过来了对应的状态文件


5发布方
- 提交准备好的事务。
- 观察准备好的事务 GID 现在已经消失(它已提交)。
- 选择插入的数据。
6订阅方
- 订阅方生成的 GID消失(提交失败)。
- 不显示已复制发布的数据。

总结
根据测试结果来看:
1、逻辑复制开启two_phase,主库COMMIT PREPARE之后,订阅节点才会把事务提交,看到结果,但是在PREPARE TRANSACTION阶段,已经把准备好的事务发送到订阅节点了。
2.逻辑复制不开启two_phase,在PREPARE TRANSACTION阶段,会把两阶段提交的状态文件传输到订阅节点,但就算发布节点COMMIT PREPARE了,因为没使用two_phase,发布节点提交成功,而订阅节点提交失败。
因此,如果在逻辑复制不使用two_phase的时候,就只能通过正常的BEGIN;COMMIT;的方式把事务发送给订阅节点 。
欢迎交流。
最后修改时间:2022-04-26 03:15:51
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




