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

子事务xid在主备节点间的同步机制

PolarDB 2025-04-10
96

子事务xid在主备节点间的同步机制

关于 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中可以解决这个问题


文章转载自PolarDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论