postgresql snapshot 快照源码解读

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 本文主要介绍数据库事务快照,分别从源码实现角度和从SQL使用角度来剖析,快照的原理,作用,用途,以及在实现过程中存在的一些差异。

postgresql snapshot快照源码解读

概述

本文主要介绍数据库事务快照,分别从源码实现角度和从SQL使用角度来剖析,快照的原理,作用,用途,以及在实现过程中存在的一些差异。

简介

数据库快照,可能有很多种理解,如在备份时,有快照备份,也是一种快照;

本文要介绍的快照,是数据库运行过程中,事务并发时,通过快照达到事务隔离,文中叫它事务快照,在postgresql中叫做snapshot。

通过事务快照,可以获得当前所有事务的一组状态,使得,我们在数据库的不同隔离级别下,可以事务内看到的数据可见性不一样,达到数据的隔离性。

快照源码分析

快照结构定义

typedef struct SnapshotData
{
   
    SnapshotType snapshot_type; /* type of snapshot */
    TransactionId xmin;            /* all XID < xmin are visible to me */
    TransactionId xmax;            /* all XID >= xmax are invisible to me */
    TransactionId *xip;
    uint32        xcnt;            /* # of xact ids in xip[] */
    TransactionId *subxip;
    int32        subxcnt;        /* # of xact ids in subxip[] */
    bool        suboverflowed;    /* has the subxip array overflowed? */

    bool        takenDuringRecovery;    /* recovery-shaped snapshot? */
    bool        copied;            /* false if it's a static snapshot */

    CommandId    curcid;            /* in my xact, CID < curcid are visible */
    uint32        speculativeToken;
    struct GlobalVisState *vistest;
    uint32        active_count;    /* refcount on ActiveSnapshot stack */
    uint32        regd_count;        /* refcount on RegisteredSnapshots */
    pairingheap_node ph_node;    /* link in the RegisteredSnapshots heap */

    TimestampTz whenTaken;        /* timestamp when snapshot was taken */
    XLogRecPtr    lsn;            /* position in the WAL stream when taken */

    uint64        snapXactCompletionCount;
} SnapshotData;

快照内容分析

  • xmin

    最小正在运行的事务ID, 初值为ShmemVariableCache->latestCompletedXid + 1;

    然后在所有backend中查找对应的xmin(也即每个backend对应快照的xmin),找最小值

  • xmax

    最大已经完成的事务ID,是ShmemVariableCache->latestCompletedXid; + 1;

  • 运行事务ID列表

    内容为 xip 和 xcnt

  • 子事务列表

    相关内容为 subxip,subxcnt,suboverflowed

  • 快照版本

    对应内容为 curXactCompletionCount

    来自 ShmemVariableCache->xactCompletionCount

    用于是否有旧快照可以快速获取,进行版本比较;

    如果版本发生变化,则需要重新获取,否则就直接使用

快照生成流程

那么我们对照快照的内容,看看各成员是如何生成;

信息介绍

在数据库运行过程中,每个backend启动时都会创建一个PGPROC的结构,在共享内存的变量ProcGlobal中有一个数组存储;

但是backend对应的 ProcGlobal数组中的下标,存储在另一个共享内存变量 procArray 中;

在每个PGPROC的结构中保存了当前backend的快照,正在运行的事务ID;

初始化

  1. xmin,xmax初始化为 初值为ShmemVariableCache->latestCompletedXid + 1

    对于xmax来讲,已经完成了,latestCompletedXid 就是最新已经完成的事务ID

  2. xip, subxip 分配内存;

扫描每个backend

那么知道上面backend事务信息的存储后,我们要想生成一个新的事务快照,就要去扫描每个backend信息;

  1. 比较xmin, 更新为最小的xmin;
  2. 遍历每个backend的xid, 与xmax比较,比xmax小的,记录 xid到快照中;
  3. 记录每个backend的 subxid到快照中; 如果子事务数据空间不足,则设置 suboverflowed 标志;

    子事务总是比父事务ID更新,所以这里丢失也没有关系。

    遍历中需要跳过的backend

  • 逻辑复制 它的xmin单独管理
  • lazy vacuum
  • 还有当前backend也不会统计在内

latestCompletedXid更新时机及规则

ShmemVariableCache->latestCompletedXid;

  • 变化规则
    • 初始化时,赋值为ShmemVariableCache->nextXid;
    • 两阶段事务完成时,在MaintainLatestCompletedXid与当前完成事务比较,取最大值 ;
    • 子事务abort时,将父子事务中最新xid与latestCompletedXid进行比较,取最大值;
    • 事务提交或abort时

oldestXmin更新时机及规则

ShmemVariableCache->oldestXid
数据库集群内的 最小的datfrozenxid

  • 更新规则
    在vacuum时,会扫描pg_database表中,每个database对应的frozenxid,取最小的作为oldestXid

xactCompletionCount更新时机及规则

ShmemVariableCache->xactCompletionCount

  • 更新规则
    • 初始化 CreateSharedProcArray 中初始化为 1
    • 在backend数量变化时 递增1 ,ProcArrayRemove中
  • 有两种场景会调用:

    • 当两阶段事务结束时,它对应额外backend proc需要回收;
    • backend退出时,proc需要回收
  • 原理

    根据变化规则,它代表了procarray版本,如果有变化就会递增
    它是一个64位整型,所以反转也没有问题,当然几乎不可能反转

快照调用

快照生成的函数接口

    GetTransactionSnapshot
        -> GetSnapshotData

>

常用的调用处

  • 事务开始和结束时
    ```c
    / 事务开始时,生成事务快照 /
    StartTransactionCommand();
    PushActiveSnapshot(GetTransactionSnapshot());
/* 事务开始时,清理事务快照 */
PopActiveSnapshot();
CommitTransactionCommand();

```

  • 在存储过程开始时
    在存储过程或者函数中也是一个完整的事务,所以事务开始,结束会生成快照

快照的优化

从生成流程看,每次生成事务快照要扫描所有的backend信息,在扫描过程是需要加ProcArrayLock共享锁的。

ProcArrayLock共享锁会阻止backend信息的变化,也就是事务的提交,代价还是相当大的。

所以在快照中增加了快照版本,当版本没有变化时,直接拿上次的快照即可。

快照的作用

生成snapshot之后,如何使用呢?

事务状态段

在snapshot中将事务状态按事务号区间分成了三部分,
由xmin, xmax组成的半闭闭开区间 [xmin, xmax)

事务可见性判断

  1. 对于xid < xmin 的部分,肯定是可见的,也就是事务已经完结;因为xmin就是最小运行的xid;

  2. 对于 xid <= xmin , 同时 xid < xmax,在此区段的事务,就需要进行检查;

    需要检查那些事务号呢? 只检查快照中记录的正在运行的事务号列表xip数组中的事务号,看它们是否完成。
    对于,读已经提交,事务完成就是可见了。

  3. 对于 xid >= xmax的,都是不可见的。因为xmax是已经完成事务的最大事务号+1,所以对于当前快照来说,超过xmax的值都是未来事务,认为它们都在运行中

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
3月前
|
消息中间件 Java 关系型数据库
实时计算 Flink版操作报错合集之从 PostgreSQL 读取数据并写入 Kafka 时,遇到 "initial slot snapshot too large" 的错误,该怎么办
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
978 0
|
SQL 关系型数据库 MySQL
Flink CDC 2.4 正式发布,新增 Vitess 数据源,PostgreSQL 和 SQL Server CDC 连接器支持增量快照,升级 Debezium 版本
Flink CDC 2.4 正式发布,新增 Vitess 数据源,PostgreSQL 和 SQL Server CDC 连接器支持增量快照,升级 Debezium 版本
1246 1
Flink CDC 2.4 正式发布,新增 Vitess 数据源,PostgreSQL 和 SQL Server CDC 连接器支持增量快照,升级 Debezium 版本
|
SQL 机器学习/深度学习 数据可视化
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(1)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(1)
1030 0
|
SQL 关系型数据库 数据挖掘
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(2)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(2)
913 0
|
SQL 关系型数据库 数据挖掘
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(3)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(3)
857 0
|
SQL 关系型数据库 数据挖掘
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(4)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL用SQL做数据分析(4)
944 0
|
运维 关系型数据库 分布式数据库
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(1)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(1)
363 0
|
关系型数据库 分布式数据库 数据库
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(2)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(2)
401 0
|
关系型数据库 Linux 分布式数据库
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(3)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(3)
327 0
|
关系型数据库 分布式数据库 PolarDB
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(4)
《PolarDB for PostgreSQL源码与应用实战》——PolarDB for PostgreSQL 基础入门(4)
227 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版
  • 下一篇
    云函数