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

PolarDB PostgreSQL 版子事务在主备节点间的同步机制

原创 PolarDB-PG 2024-07-24
177

关于 PolarDB PostgreSQL 版

PolarDB PostgreSQL 版是一款阿里云自主研发的云原生关系型数据库产品,100% 兼容 PostgreSQL,高度兼容Oracle语法;采用基于 Shared-Storage 的存储计算分离架构,具有极致弹性、毫秒级延迟、HTAP 、Ganos全空间数据处理能力和高可靠、高可用、弹性扩展等企业级数据库特性。同时,PolarDB PostgreSQL 版具有大规模并行计算能力,可以应对 OLTP 与 OLAP 混合负载。

背景

本文主要介绍postgresql的子事务在主节点和备节点间是如何进行同步的。

哪些场景下会用到子事务

  1. savepoint

使用场景举例:

BEGIN;

-- 执行某些操作
...

-- 创建保存点A
SAVEPOINT savepoint_a;

-- 执行一些可能失败的操作,这些操作可能不会影响前面的操作
...

-- 如果成功则继续,否则回滚到保存点A
-- ROLLBACK TO SAVEPOINT savepoint_a;

-- 创建另一个保存点B
SAVEPOINT savepoint_b;

...

-- 如果第二批操作失败,则可以选择回滚到保存点B
-- ROLLBACK TO SAVEPOINT savepoint_b;

-- 如果所有操作均成功,则可以提交整个事务
COMMIT;

  1. 另外在存储过程中,也可以开启子事务

子事务的xid是如何传送到备节点的

分为下面两种情况:

当前事务分配了过多子事务,超过了PGPROC_MAX_CACHED_SUBXIDS

  1. 主节点

a. 主节点在开启子事务的时候,会通过 AssignTransactionId 函数给子事务生成xid,同时会在主节点的subtrans SLRU中维护subxid 与 parentxid的映射关系

b. 主节点在AssignTransactionId时,会计数unreported subxid,如果当前事务,开启的subxid数量达到 PGPROC_MAX_CACHED_SUBXIDS 个时,就会把这些subxid信息放入WAL中,日志类型就是XLOG_XACT_ASSIGNMENT,内容就是topxid与subxids

typedef struct xl_xact_assignment
{
TransactionId xtop; /* assigned XID's top-level XID */
int nsubxacts; /* number of subtransaction XIDs */
TransactionId xsub[FLEXIBLE_ARRAY_MEMBER]; /* assigned subxids */
} xl_xact_assignment;

c. 通过 XLOG_XACT_ASSIGNMENT 类型的WAL传送到备节点

对应的代码可以参考:

AssignTransactionId
-> GetNewTransactionId
-> SubTransSetParent
-> XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT)

  1. 备节点

备节点维护了一个名为KnownAssignedXids的数组,用来同步记录收到的事务或子事务id。

备节点一直处于回放WAL状态中,在 StartupXLOG 中不断apply各种收到的WAL日志,当收到XLOG_XACT_ASSIGNMENT时,会在subtrans中记录subxid与topxid的映射关系,并且从KnownAssignedXids数组中删除

具体代码可以参考

处理 XLOG_XACT_ASSIGNMENT 日志
StartupXLOG
-> rm_redo
-> xact_redo
-> ProcArrayApplyXidAssignment
-> RecordKnownAssignedTransactionIds
-> SubTransSetParent
-> KnownAssignedXidsRemoveTree

当前事务分配了少量子事务,没有超过PGPROC_MAX_CACHED_SUBXIDS

在备节点回放WAL时,会将读到的xid放入到KnownAssignedXids数组中,当回放到事务提交或回滚的WAL时,就会将相关xid从KnownAssignedXids数组中删除。

这个过程中,子事务的xid不会放入到subtrans中,而是与父事务的xid一起放在KnownAssignedXids数组中。

当回放到事务提交或回滚的WAL时,会将subxid和xid从数组中删除。

具体代码可以参考

StartupXLOG
-> rm_redo
-> xact_redo
-> xact_redo_commit
-> RecordKnownAssignedTransactionIds
-> ExpireTreeKnownAssignedTransactionIds

主节点和备节点是如何维护 subtrans 的

从上面的流程中,可以总结出主备节点对subtrans的维护方式是不同的:

1. 向subtrans写入内容,是不会写入对应的WAL的

2. truncate subtrans的时机,主节点是在checkpoint时,备节点是在restartpoint时

3. 主节点在AssignTransactionId时,就会在subtrans中记录subxid和parentxid

4. 备节点需要根据XLOG_XACT_ASSIGNMENT才可以得到subxid与topxid的关系,然后在备节点的subtrans里构建出这个关系,同时,会从knownassignedxids中,将这些subxid删除。 因为KnownAssignedXids中记录的是xid和subxid,但如果subxid分配过多,过多的subxid在KnownAssignedXids中会有使数组溢出的风险,放到subtrans中可以解决这个问题

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

评论