本文对Multi-Master架构的关键技术点进行介绍,包括分布式事务处理、全局死锁处理、DDL支持、分布式表锁支持、集群容错和高可用能力。

分布式事务管理

  • AnalyticDB PostgreSQL版分布式事务

    AnalyticDB PostgreSQL版通过二阶段提交协议(2PC)来实现分布式事务,同时使用了分布式快照来保证Master和不同Segment间的数据一致性。

    分布式事务-ADBPG

    分布式事务由Main Master发起,通过2PC协议提交到Segment。2PC协议将整体事务的提交过程拆分成了Prepare和Commit/Abort两个阶段,如上图所示,只有参与事务的所有Segment都成功提交整体事务才会成功提交。如果在第一阶段有存在Prepare失败的Segment,则整个事务会终止;如果在第二阶段有Commit失败的Segment,而且Master已经成功记录了PREPARED日志,则会发起重试。如果一个事务仅牵涉1个Segment,系统会按照1PC的方式来提交事务从而提升性能。1PC协议中Master参与协调的Prepare和Commit两个阶段将合二为一,最终由唯一参与的Segment来保证事务执行的原子性。

    Main Master上的GTM全局事务管理组件会维护全局的分布式事务状态,每一个事务都会产生一个新的分布式事务ID、设置时间戳及相应的状态信息,在获取快照时,创建分布式快照并保存在当前快照中。以下是分布式快照记录的核心信息:

    typedef struct DistributedSnapshot
    {
        DistributedTransactionTimeStamp distribTransactionTimeStamp;
        DistributedTransactionId xminAllDistributedSnapshots;
        DistributedSnapshotId distribSnapshotId;
    
        DistributedTransactionId xmin; /* XID < xmin 则可见 */
        DistributedTransactionId xmax;  /* XID >= xmax 则不可见 */
    
        int32count; /* inProgressXidArray 数组中分布式事务的个数 */
        DistributedTransactionId *inProgressXidArray; /* 正在执行的分布式事务数组 */
    } DistributedSnapshot;

    执行查询时,Main Master将分布式事务和快照等信息序列化,通过libpq协议发送到Segment执行。Segment反序列化后,获得对应分布式事务和快照信息,并以此为依据来判定查询到的元组的可见性。所有参与该查询的Segment都使用同一份分布式事务和快照信息判断元组的可见性,从而保证整个实例数据的一致性。同时,AnalyticDB PostgreSQL版提供了本地事务和分布式事务提交缓存,用以帮助快速查询本地事务ID(XID)和分布式全局事务ID(GXID)的映射关系。

    说明 AnalyticDB PostgreSQL版会保存全局事务的提交日志,用以判断某个事务是否已经提交。
    ADBPG分布式事务-示例

    如上图所示,Txn A在插入一条数据后,Txn B对该数据进行了更新。基于PostgreSQL的MVCC机制,当前Heap表中会存在两条对应的记录,Txn B更新完数据后会将原来元组(Tuple)对应的xmax改为自身的本地XID值(由0改为4)。此后,Txn C和Txn D两个查询会结合自己的分布式快照信息来做可见性判断,具体规则如下:

    • 如果GXID的值小于distribedSnapshot->xmin,则元组可见。
    • 如果GXID的值大于distribedSnapshot->xmax,则元组不可见。
    • 如果distribedSnapshot->inProgressXidArray包含GXID的值,则元组不可见。
    • 如果distribedSnapshot->inProgressXidArray不包含GXID的值,则元组可见。

    如果不能根据分布式快照判断可见性,或者不需要根据分布式快照判断可见性,则使用本地快照信息判断,判断逻辑与原生PostgreSQL的判断可见性逻辑一致。

    基于上述规则,Txn C查到两条元组记录后,通过XID和GXID映射关系找到两条记录对应的GXID值(分别为100, 105),规则会限定Txn B的更新对Txn C不可见,所以Txn C查询到的结果是foo;而Txn D基于规则则对Txn B更新后的Tuple可见,所以查询到的是bar

  • Multi-Master分布式事务多Master分布式事务

    Multi-Master的分布式事务是在原有分布式事务基础之上进行了增强。如上图所示,Postmaster是守护进程,Main Master的Backend业务处理进程和GTM Server之间通过共享内存通信,但Secondary Master是无法直接通过共享内存与Main Master上的GTM Server通信的,为此,AnalyticDB PostgreSQL版在Secondary Master和Main Master之间新增了一条通道并实现了一套GTM交互协议。

    为了减少Secondary Master和Main Master之间的连接并提升网络通信效率,AnalyticDB PostgreSQL版新增了GTM Proxy来处理同一个Secondary Master上多个Backend进程的GTM请求。以下内容将从GTM交互协议、GTM Proxy和分布事务恢复三个方面来介绍Multi-Master分布式事务实现的技术细节。

    • GTM交互协议

      GTM交互协议是Secondary Master和Main Master之间事务交互的核心协议,协议的核心消息以及说明如下所示。

      协议核心消息 说明
      GET_GXID 分配GXID。
      SNAPSHOT_GET 获取分布式快照。
      TXN_BEGIN 创建新事务。
      TXN_BEGIN_GETGXID 创建新事务,并分配GXID。
      TXN_PREPARE 指定的事务完成2PC的PREPARE阶段。
      TXN_COMMIT 提交指定的事务。
      TXN_ROLLBACK 回滚指定的事务。
      TXN_GET_STATUS 获取属于指定Master的所有事务状态信息。
      GET_GTM_READY 检查GTM SERVER是否可服务正常事务请求。
      SET_GTM_READY 设置GTM SERVER可服务正常事务请求。
      TXN_COMMIT_RECOVERY Master恢复阶段提交指定的事务。
      TXN_ROLLBACK_RECOVERY Master恢复阶段回滚指定的事务。
      CLEANUP_MASTER_TRANS 恢复完时清除Master的剩余事务。

      通过上表可以看出,消息的核心依旧是交换GXID、SNAPSHOT等信息,同时进行BEGIN、PREPARE、COMMIT、ABORT等事务操作。由于跨节点消息交互成本较高,考虑到OLAP用户的特点和需求,AnalyticDB PostgreSQL版配合协议提供了不同的一致性选项,从而让您可以在性能和一致性上进行权衡和选择。

      • 会话一致:同一个会话满足可预期的一致性要求,包括单调读,单调写,读自己所写,读后写的一致性。
      • 强一致:线性一致性,一旦操作完成,所有会话可见。也基于不同的一致性模式进行了定制和精简。
      模式 事务类型 事务策略 是否保证原子性(A) 隔离级别(I) 是否保证持久性(D)
      会话一致(更高性能) 跨Segment 2PC,共享本地快照 RU/RC(会话内)
      单Segment 1PC,共享本地快照 RC
      强一致(更完善的ACID保证) 跨Segment 2PC,分布式快照 RC,RR
      单Segment 1PC,分布式快照 RC,RR

      如果您需要更高的性能而对于一致性可以做出一定妥协,则可以选择会话一致模式,相比强一致,会话一致对协议交互进行了大幅度精简,仅仅保留了GET_GXID和GET_GXID_MULTI核心消息。

      在会话一致模式下,Secondary Master只需要从Main Master获取全局的GXID信息,然后结合本地快照并配合重试及全局死锁检测(GDD)来独立处理事务,大幅度简化与Master之间的消息交互从而提升性能。

      协议核心消息 说明
      GET_GXID 分配GXID。
      GET_GXID_MULTI 批量分配GXID。
    • GTM Proxy

      在Multi-Master架构中,GTM Proxy作为Postmaster的子进程来进行管理,优点如下:

      • 无需新增角色,配套管控更简单。
      • GTM Proxy和Backend之间天然认证和互信。
      • GTM Proxy可以通过共享内存和Backend进程通信,相比Tcp Loopback更高效,既可以减少内存拷贝,也没有Network Stack开销。

      每个GTM Proxy进程会和GTM Server建立一个网络连接,并会服务多个本地的Backend进程,将它们的GTM请求转发给GTM Server。GTM Proxy还针对性的做一些请求优化处理,例如:

      • 多个Backend间共享Snapshot,从而减少Snapshot请求数。
      • 合并和批量处理Backend的并发GTM请求。
      • 批量获取GXID(会话一致)。

      GTM Proxy是减少Secondary Master和Main Master之间连接并提升网络通信效率的关键。在使用过程中,如果您开启了强一致模式,AnalyticDB PostgreSQL版在Main Master上会默认开启GTM Proxy来代理Main Master上多个Backend进程与GTM Server之间的请求,从而进一步降低GTM Server的压力。

    • 分布事务恢复

      在很多场景下系统都需要进行恢复分布式事务操作,例如系统或Master重启;Main Master与Standby Master切换等。当不考虑Multi-Master架构时,恢复分布式事务可以简单划分为如下步骤:

      1. Main Master回放XLOG,找出所有已经就绪(Prepared)但是尚未提交(Committed)的事务。
      2. 命令所有Segment提交所有需要Committed的事务。
      3. 收集所有Segment上未Committed而且不在Main Master需要提交的事务列表中的事务,终止这些事务。

      如果引入Multi-Master架构,则会出现一些新的问题,核心问题如下:

      • 如何恢复Secondary Master发起的事务。
      • Segment和Secondary Master上残留Prepared阶段的事务在Secondary Master或者Master重启等情况下如何恢复或清理等。

      为了解决上述问题,AnalyticDB PostgreSQL版对二阶段事务的提交和分布式事务的恢复流程都做了增强,下图为二阶段事务提交的增强和Secondary Master被删除及第一次启动时对应的清理流程。

      恢复分布式事务

      此外,AnalyticDB PostgreSQL版对Main Master和Secondary Master重启的流程也进行了增强,与单独Main Master重启恢复的差别在于需要区分出属于自己发起的分布式事务,区分方式通过增强GXID来实现。AnalyticDB PostgreSQL版在原本GXID的基本信息之上添加了MasterID信息,GXID和MasterID结合后,就可以基于GXID来区分出事务属于的Master。

全局死锁检测

AnalyticDB PostgreSQL 4.3版是通过对表加写锁来避免执行UPDATE和DELETE时出现全局死锁,虽然这个方法避免了全局死锁,但是并发更新性能很差。AnalyticDB PostgreSQL 6.0版开始引入了全局死锁检测。该检测进程收集并分析集群中的锁等待信息,如果发现了死锁则结束造成死锁的进程来解除死锁,极大地提高了高并发情况下简单查询、插入、删除和更新操作的性能。

AnalyticDB PostgreSQL 6.0版实现全局死锁检测的特征如下:

  • 全局死锁检测服务进程(GDD)运行在Main Master上。
  • GDD会周期性获取所有Segment上的分布式事务的GXID及其等待关系。
  • GDD会构造全局的事务等待关系图,检测是否成环。如果成环,则回滚环中一个事务,破解死锁。
全局死锁检测

AnalyticDB PostgreSQL版Multi-Master新增了Get_gxidsCancel_deadlock_txn的RPC调用,功能介绍如下:

  • Get_gxids:从每个Secondary Master获取GXID列表,以判断导致死锁的事务属于哪些Master。
  • Cancel_deadlock_txn:如果导致死锁的事务属于某个Secondary Master,则请求该Master回滚该事务。

DDL支持

在早期AnalyticDB PostgreSQL版中,是通过2PC的方式来实现Main Master的DDL支持以及与Segment上Catalog的修改同步。AnalyticDB PostgreSQL版Multi-Master扩展了这一功能来支持对Secondary Master上Catalog的同步。具体流程如下图所示。

DDL支持-1

此外,Secondary Master也支持处理DDL,AnalyticDB PostgreSQL版在Secondary Master内部实现了一个简单的代理,Secondary Master如果收到DDL请求,会将请求转发给Main Master来处理。具体如下图所示。

DDL支持-2

分布式表锁

在数据库中,并发访问表数据通常都是通过锁来实现的。AnalyticDB PostgreSQL版的锁模型与PostgreSQL锁模型相兼容,锁模型具体信息如下所示。

请求锁模型(Requested Lock Mode) 当前锁模型(Current Lock Mode)
ACCESS SHARE ROW SHARE ROW EXCLUSIVE SHARE UPDATE EXCLUSIVE SHARE SHARE ROW EXCLUSIVE EXCLUSIVE ACCESS EXCLUSIVE
ACCESS SHARE ×
ROW SHARE × ×
ROW EXCLUSIVE × × × ×
SHARE UPDATE EXCLUSIVE × × × × ×
SHARE × × × × ×
SHARE ROW EXCLUSIVE × × × × × ×
EXCLUSIVE × × × × × × ×
ACCESS EXCLUSIVE × × × × × × × ×
说明
  • √表示可以同时持有锁。
  • ×表示不能同时持有锁。

AnalyticDB PostgreSQL版对Multi-Master架构下的表锁协议进行了增强和适配,AnalyticDB PostgreSQL版定义了一套新的分布式表锁协议来规范Main Master及Secondary Master上加锁的顺序和规则:

  • 任意Master上的进程请求1~3级锁规则如下:
    • 本地请求该表锁。
    • 在所有Segment上请求该表锁。
    • 事务结束时所有节点释放锁。
  • Main Mater上的进程请求4~8级锁规则如下:
    • 本地请求该表锁。
    • 在所有Secondary Master上请求该表锁。
    • 在所有Segment上请求该表锁。
    • 事务结束时所有节点释放锁。
  • Secondary Master上的进程请求4~8级锁规则如下:
    • 在Main Master上请求该表锁。
    • 本地请求该表锁。
    • 在所有其他Secondary Master上请求该表锁。
    • 在所有Segment上请求该表锁。
    • 事务结束时所有节点释放锁。

基于上述规则,AnalyticDB PostgreSQL版可以实现任何表锁请求会最终在某个Master或者Segment得到裁决,从而保证了对原表锁协议的兼容。

容错与高可用

AnalyticDB PostgreSQL版Multi-Master架构在原AnalyticDB PostgreSQL版的容错和高可用基础之上进行了增强,让系统能够进一步对Secondary Master进行兼容。如果Secondary Master故障,则会由管控系统看护并做实时修复。

AnalyticDB PostgreSQL版通过复制和监控来实现容错和高可用,具体如下:

  • Standby Master和Mirror Segment分别为Main Master和Primary Segment提供副本(通过PG流复制实现)。
  • FTS在后台负责监控与主备切换。
容错和高可用

容错和高可用具体工作流程如下:

  1. 步骤A为Main Master到Standby Master的流复制。
  2. 步骤B为Primary Segment到Mirror segment的流复制。
  3. 步骤C为Main Master的FTS Probe进程发包探活Primary Segment。
  4. 步骤D为Main Master的FTS Probe进程发包探活Secondary Master。
  5. 步骤E为Main Master重启后,其FTS Probe进程向GTM Server通报所有Master。
  6. 步骤F为Secondary Master的FTS Probe发包探活Main Master,获取最新集群配置和状态信息并保存在本地。
  7. 步骤G为Secondary Master的FTS Probe无法连接Main Master后尝试探活Standby master,若成功则更新其为新的Main Master;否则继续探活原Main Master。