暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

PostgreSQL-15逻辑复制发布/订阅的两阶段提交功能测试

原创 阎书利 2022-04-24
995

数据库版本:
1650790264954.png

一、启动两阶段提交

1发布方

  • 创建表和发布。
postgres=# CREATE TABLE test (col1 INT, col2 TEXT, PRIMARY KEY(col1));
CREATE TABLE
postgres=# CREATE PUBLICATION pub FOR TABLE test;

1650791086628.png

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)

1650791418122.png

1650791722831.png

相应日志为

发布节点
1650791543680.png

订阅节点

1650791524546.png

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设置为非零的值,然后重启数据库服务即可 。
1650791873629.png

参数修改后,正确的如下
1650792220588.png

4订阅方

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

1650792255968.png

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

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

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)

1650792345495.png

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)

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

二、不启动两阶段提交

1发布方

  • 创建表和发布。
      postgres=# CREATE TABLE test2 (col1 INT, col2 TEXT, PRIMARY KEY(col1));
      CREATE TABLE
      postgres=# CREATE PUBLICATION pub FOR TABLE test2;

1650793030218.png

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)

1650793353339.png

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)

1650798805142.png

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)

1650798826038.png

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

1650798987523.png
1650799019336.png

5发布方

  • 提交准备好的事务。
  • 观察准备好的事务 GID 现在已经消失(它已提交)。
  • 选择插入的数据。

6订阅方

  • 订阅方生成的 GID消失(提交失败)。
  • 不显示已复制发布的数据。
    1650799199608.png

总结

根据测试结果来看:
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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论