关于 PolarDB PostgreSQL 版
PolarDB PostgreSQL 版是一款阿里云自主研发的云原生关系型数据库产品,100% 兼容 PostgreSQL,高度兼容Oracle语法;采用基于 Shared-Storage 的存储计算分离架构,具有极致弹性、毫秒级延迟、HTAP 、Ganos全空间数据处理能力和高可靠、高可用、弹性扩展等企业级数据库特性。同时,PolarDB PostgreSQL 版具有大规模并行计算能力,可以应对 OLTP 与 OLAP 混合负载。
背景
本文主要介绍postgresql的子事务在主节点和备节点间是如何进行同步的。
哪些场景下会用到子事务
- savepoint
使用场景举例:
BEGIN;
-- 执行某些操作
...
-- 创建保存点A
SAVEPOINT savepoint_a;
-- 执行一些可能失败的操作,这些操作可能不会影响前面的操作
...
-- 如果成功则继续,否则回滚到保存点A
-- ROLLBACK TO SAVEPOINT savepoint_a;
-- 创建另一个保存点B
SAVEPOINT savepoint_b;
...
-- 如果第二批操作失败,则可以选择回滚到保存点B
-- ROLLBACK TO SAVEPOINT savepoint_b;
-- 如果所有操作均成功,则可以提交整个事务
COMMIT;
- 另外在存储过程中,也可以开启子事务
子事务的xid是如何传送到备节点的
分为下面两种情况:
当前事务分配了过多子事务,超过了PGPROC_MAX_CACHED_SUBXIDS
- 主节点
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)
- 备节点
备节点维护了一个名为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中可以解决这个问题




