当前位置: 首页 > news >正文

PolarDB数据库的CSN机制

背景

对postgres数据库熟悉的同学会发现在高并发场景下在获取快照处易出现性能瓶颈,其原因在于PG使用全局数组在共享内存中保存所有事务的状态,在获取快照时需要加锁以保证数据一致性。获取快照时需要持有ProcArraryLock共享锁比遍历ProcArray数组中活跃事务,与此同时提交或回滚的事务需要申请ProcArray排他锁已清除本事务。可想而知,在高并发场景下对ProcArrayLock的申请会成为数据库的瓶颈。为克服上述问题,polardb引入CSN(COMMIT SEQUENCE NUM)事务快照机制避免对ProcarryLock的申请。

1 CSN 机制

1.1 CSN原理

PolarDB在事务层,通过CSN快照来代替PG原生快照
在这里插入图片描述
如图所示,每个非只读事务在运行过程中会被分配一个xid,在事务提交时推进CSN;同时会将单前的CSN与事务的XID的映射关系保存起来。
图中实心竖线标识获取快照时刻,会获取最新提交CSN的下一个值4。TX1、TX3、TX5均已提交,其对应的CSN为1、2、3。TX2、TX4、TX6正在运行,TX6、TX8是未来还未开启的事务。对于当前快照而言,严格小于CSN=4的事务的提交结果均可见;其余事务还未提交,不可见。

1.2 CSN的实现

CSN(Commit Sequence Number,提交顺序号)本身与XID(事务号)也会留存一个映射关系,以便将事务本身以及其对应的可见性进行关联,这个映射关系会留存在CSNLog中。事务ID 2048、2049、2050、2051、2052、2053对应的CSN号依次是5、4、7、10、6、8,也就是事务的提交顺序是2049、2048、2052、2050、2053、2051.
在这里插入图片描述
PolarDB与之对应为每个事务id分配8个字节uint64的CSN号,所以一个8kB页面能保存1k个事务的CSN号。CSNLOG达到一定大小后会分块,每个CSNLOG文件块的大小为256kB。同xid号类似,CSN号预留了几个特殊的号。CSNLOG定义代码如下:
在这里插入图片描述

2 CSN快照与可见性判断

2.1 CSN相关数据结构

polar_csn_mvcc_var_cache结构体维护了最老的活跃事务xid、下一个将要分配的CSN以及最新完成的事务xid。
在这里插入图片描述
当其他事务要获取该事务的CSN状态时,如果该事务处于正在提交阶段,那么其他事务通过获取CommitSeqNoLock锁的排他模式来等待其完成。
CSNLogControlLock用于写入csnlog文件时加锁保护。

2.2 CSN快照的获取

PolarDB中获取CSN快照函数为GetSnapshotDataCSN,实现流程如下:
1、获取polar_shmem_csn_mvcc_var_cache->polar_next_csn作为snapshot->polar_snapshot_csn值。
2、snapshot->xmin = polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid
3、snapshot->xmax=polar_shmem_csn_mvcc_var_cache->polar_latest_completed_xid+1
4、根据GUC参数old_snapshot_threshold,决定是否需要设置snapshot->lsn以及snapshot->whenTaken 。
5、最后根据GUC参数polar_csn_xid_snapshot表示是否从csn快照中生成xid快照。

tatic Snapshot
GetSnapshotDataCSN(Snapshot snapshot)
{TransactionId xmin;TransactionId xmax;CommitSeqNo snapshotcsn;Assert(snapshot != NULL);/** The ProcArrayLock is not needed here. We only set our xmin if* it's not already set. There are only a few functions that check* the xmin under exclusive ProcArrayLock:* 1) ProcArrayInstallRestored/ImportedXmin -- can only care about* our xmin long after it has been first set.* 2) ProcArrayEndTransaction is not called concurrently with* GetSnapshotData.*//* Anything older than oldestActiveXid is surely finished by now. */xmin = pg_atomic_read_u32(&polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid);/* If no performance issue, we try best to maintain RecentXmin for xid based snapshot */RecentXmin = xmin;/* Announce my xmin, to hold back GlobalXmin. */if (!TransactionIdIsValid(MyPgXact->xmin)){TransactionId oldest_active_xid;MyPgXact->xmin = xmin;TransactionXmin = xmin;/** Recheck, if oldestActiveXid advanced after we read it.** This protects against a race condition with GetRecentGlobalXmin().* If a transaction ends runs GetRecentGlobalXmin(), just after we fetch* polar_oldest_active_xid, but before we set MyPgXact->xmin, it's possible* that GetRecentGlobalXmin() computed a new GlobalXmin that doesn't* cover the xmin that we got. To fix that, check polar_oldest_active_xid* again, after setting xmin. Redoing it once is enough, we don't need* to loop, because the (stale) xmin that we set prevents the same* race condition from advancing RecentGlobalXmin again.** For a brief moment, we can have the situation that our xmin is* lower than RecentGlobalXmin, but it's OK because we don't use that xmin* until we've re-checked and corrected it if necessary.*//** memory barrier to make sure that setting the xmin in our PGPROC entry* is made visible to others, before the read below.*/pg_memory_barrier();oldest_active_xid  = pg_atomic_read_u32(&polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid);if (oldest_active_xid != xmin){/*no cover begin*/xmin = oldest_active_xid;RecentXmin = xmin;MyPgXact->xmin = xmin;TransactionXmin = xmin;/*no cover end*/}}/** Get the current snapshot CSN. This* serializes us with any concurrent commits.*/snapshotcsn = pg_atomic_read_u64(&polar_shmem_csn_mvcc_var_cache->polar_next_csn);/** Also get xmax. It is always latestCompletedXid + 1.* Make sure to read it after CSN (see TransactionIdAsyncCommitTree())*/pg_read_barrier();xmax = pg_atomic_read_u32(&polar_shmem_csn_mvcc_var_cache->polar_latest_completed_xid);Assert(TransactionIdIsNormal(xmax));TransactionIdAdvance(xmax);snapshot->xmin = xmin;snapshot->xmax = xmax;snapshot->polar_snapshot_csn = snapshotcsn;snapshot->polar_csn_xid_snapshot = false;snapshot->xcnt = 0;snapshot->subxcnt = 0;snapshot->suboverflowed = false;snapshot->curcid = GetCurrentCommandId(false);/** This is a new snapshot, so set both refcounts are zero, and mark it as* not copied in persistent memory.*/snapshot->active_count = 0;snapshot->regd_count = 0;snapshot->copied = false;if (old_snapshot_threshold < 0){/** If not using "snapshot too old" feature, fill related fields with* dummy values that don't require any locking.*/snapshot->lsn = InvalidXLogRecPtr;snapshot->whenTaken = 0;}else{/** Capture the current time and WAL stream location in case this* snapshot becomes old enough to need to fall back on the special* "old snapshot" logic.*/snapshot->lsn = GetXLogInsertRecPtr();snapshot->whenTaken = GetSnapshotCurrentTimestamp();MaintainOldSnapshotTimeMapping(snapshot->whenTaken, xmin);}/* * We get RecentGlobalXmin/RecentGlobalDataXmin lazily in polar csn.* In master mode, we reset it when end transaction;* In hot standby mode, wal replayed by startup backend, we has to reset* it when get snapshot,* because RecentGlobalXmin/RecentGlobalDataXmin are backend variables.*/if (RecoveryInProgress())resetGlobalXminCacheCSN();/* * We need xid snapshot, should generate it from csn snapshot.* The logic is:* 1. Scan csnlog from xmin(inclusive) to xmax(exclusive)* 2. Add xids whose status are in_progress or committing or *    committed csn >= snapshotcsn to xid array* Like hot standby, we don't know which xids are top-level and which are* subxacts. So we use subxip to store xids as more as possible. */if (polar_csn_xid_snapshot){if (TransactionIdPrecedes(xmin, xmax))polar_csnlog_get_running_xids(xmin, xmax, snapshotcsn, GetMaxSnapshotSubxidCount(),&snapshot->subxcnt, snapshot->subxip, &snapshot->suboverflowed);snapshot->polar_csn_xid_snapshot = true;}return snapshot;
}
2.3 MVCC可见性判断流程

结合行头的结构(其中的xmin、xmax)以及Clog、上述CSNLOG的映射机制,MVCC的大致判断流程如下所示,实现函数为HeapTupleSatisfiesMVCC,对于xid在CSN快照中的可见性判断函数为XidVisibleInSnapshotCSN,其流程图如下:
在这里插入图片描述

2.4 事务commit和abort如何更新CSN

CSN快照获取主要依据polar_shmem_csn_mvcc_var_cache变量中维护的成员变量,参考前面的CSN快照获取。
因此,这里主要关注事务在commit和abort时如何更新polar_shmem_csn_mvcc_var_cache的成员变量。

AdvanceOldestActiveXidCSN函数用于推进->polar_oldest_active_xid这个值:
进程退出、事务提交以及回滚之后、以及在备机上回放commit和abort时需要推进polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid,当事务的xid等于polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid时,才会推进polar_shmem_csn_mvcc_var_cache->polar_oldest_active_xid的值,否则直接返回。

polar_xact_abort_tree_csn在事务回滚时设置CSN的值(POLAR_CSN_ABORTED),并推进polar_shmem_csn_mvcc_var_cache->polar_latest_completed_xid值。
polar_xact_commit_tree_csn在事务提交时设置该事务CSN的值,并推进和polar_shmem_csn_mvcc_var_cache->polar_latest_completed_xid和polar_shmem_csn_mvcc_var_cache->polar_next_csn的值。

polar_shmem_csn_mvcc_var_cache->polar_next_csn只有事务提交才会推进,回滚事务不会推进该值。

对于开启CSN功能之后,PG中原来的维护xid分配的全局变量ShmemVariableCache中的数据成员只有ShmemVariableCache->nextXid会更新(用于分配xid)。而原来的ShmemVariableCache->latestCompletedXid等在已经被polar_shmem_csn_mvcc_var_cache->polar_latest_completed_xid所取代,因此事务状态变化时并不需要维护其值

相关文章:

PolarDB数据库的CSN机制

背景 对postgres数据库熟悉的同学会发现在高并发场景下在获取快照处易出现性能瓶颈&#xff0c;其原因在于PG使用全局数组在共享内存中保存所有事务的状态&#xff0c;在获取快照时需要加锁以保证数据一致性。获取快照时需要持有ProcArraryLock共享锁比遍历ProcArray数组中活跃…...

使用kubeadm 部署kubernetes 1.26.1集群 Calico ToR配置

目录 机器信息 升级内核 系统配置 部署容器运行时Containerd 安装crictl客户端命令 配置服务器支持开启ipvs的前提条件 安装 kubeadm、kubelet 和 kubectl 初始化集群 &#xff08;master&#xff09; 安装CNI Calico 集群加入node节点 机器信息 主机名集群角色IP内…...

Servlet笔记(11):Servletcontext对象

1、什么是ServletContext ServletContext是一个全局储存空间&#xff0c;随服务器的生命周期变化&#xff0c; Cookie&#xff0c;Session&#xff0c;ServletContext的区别 Cookie&#xff1a; 存在于客户端的本地文本文件 Session&#xff1a; 存在于服务器的文本文件&#…...

EM算法是什么

EM算法是什么 EM算法&#xff08;Expectation-Maximization Algorithm&#xff09;是一种用于参数估计的迭代算法。它常被用于含有隐变量&#xff08;latent variable&#xff09;的概率模型中&#xff0c;例如高斯混合模型、隐马尔可夫模型等。 EM算法分为两个步骤&#xff…...

C++---线性dp---方格取数(每日一道算法2023.2.25)

注意事项&#xff1a; 本题属于"数字三角形"和"摘花生"两题的进阶版&#xff0c;建议优先看懂那两道&#xff0c;有助理解。 题目&#xff1a; 输入: 8 2 3 13 2 6 6 3 5 7 4 4 14 5 2 21 5 6 4 6 3 15 7 2 14 0 0 0输出&#xff1a; 67#include <cm…...

《第一行代码》 第八章:应用手机多媒体

一&#xff0c;使用通知 第一步&#xff0c;创建项目&#xff0c;书写布局 <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:orientation"vertical"android:layout_width"match_parent"android:layout_he…...

C++设计模式(20)——迭代器模式

亦称&#xff1a; Iterator 意图 迭代器模式是一种行为设计模式&#xff0c; 让你能在不暴露集合底层表现形式 &#xff08;列表、 栈和树等&#xff09; 的情况下遍历集合中所有的元素。 问题 集合是编程中最常使用的数据类型之一。 尽管如此&#xff0c; 集合只是一组对…...

戴尔Latitude 3410电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板戴尔Latitude 3410处理器英特尔酷睿i7-10510U已驱动内存8GB已驱动硬盘SK hynix BC511 NVMe SSD已驱动显卡Intel UHD 620Nvidia GeForce MX230(屏蔽)无法驱动声卡Realtek ALC236已驱动网卡Realtek RTL81…...

一起Talk Android吧(第五百零四回:如何调整组件在约束布局中的位置)

文章目录 背景介绍调整方法一调整方法二经验分享各位看官们大家好,上一回中咱们说的例子是"解决retrofit被混淆后代码出错的问题",这一回中咱们说的例子是" 如何调整组件在约束布局中的位置"。闲话休提,言归正转, 让我们一起Talk Android吧! 背景介绍…...

ssh连不上实验室的物理机了

实验室的电脑&#xff0c;不能在校外用 ssh 连接了 192.168.1.33 是本地地址&#xff0c;掩码16位&#xff0c;图1。 192.168.1.14 是实验室的另一台可以ssh连接的物理机&#xff0c;掩码16。 192.168.0.1 是无线路由器地址。 192.168.0.2 是192.168.1.14上的虚拟机地址&#…...

selinux讲解

Selinux讲解 1、selinux的概述 Selinux的历史 Linux安全性与windows在不开启防御措施的时候是一样的&#xff1b;同样是C2级别的安全防护安全级别评定&#xff1a; D–>C1–>C2–>B1–>B2–>B3–>A1 D级&#xff0c;最低安全性C1级&#xff0c;主存取控制…...

【计算机网络】TCP底层设计交互原理

文章目录1.TCP底层三次握手详细流程2.TCP洪水攻击介绍和ss命令浅析3.Linux服务器TCP洪水攻击入侵案例4.TCP洪水攻击结果分析和解决方案5.TCP底层四次挥手详细流程1.TCP底层三次握手详细流程 TCP的可靠性传输机制&#xff1a;TCP三次我手的流程 一次握手&#xff1a;客户端发送一…...

Kotlin1.8新特性

Kotlin1.8.0新特性 新特性概述 JVM 的新实验性功能&#xff1a;递归复制或删除目录内容提升了 kotlin-reflect 性能新的 -Xdebug 编译器选项&#xff0c;提供更出色的调试体验kotlin-stdlib-jdk7 与 kotlin-stdlib-jdk8 合并为 kotlin-stdlib提升了 Objective-C/Swift 互操作…...

【Java8】

1、接口中默认方法修饰为普通方法 在jdk8之前&#xff0c;interface之中可以定义变量和方法&#xff0c;变量必须是public、static、final的&#xff0c;方法必须是public、abstract的&#xff0c;由于这些修饰符都是默认的。 接口定义方法: public抽象方法需要子类实现 接口定…...

阿里 Java 程序员面试经验分享,附带个人学习笔记、路线大纲

背景经历 当时我工作近5年&#xff0c;明显感觉到了瓶颈期。说句不好听的成了老油条&#xff0c;可以每天舒服的混日子&#xff08;这也有好处&#xff0c;有时间准备面试&#xff09;。这对于个人成长不利&#xff0c;长此以往可能面临大龄失业。所以我觉得需要痛下决心改变一…...

十大算法基础——上(共有20道例题,大多数为简单题)

一、枚举&#xff08;Enumerate&#xff09;算法 定义&#xff1a;就是一个个举例出来&#xff0c;然后看看符不符合条件。 举例&#xff1a;一个数组中的数互不相同&#xff0c;求其中和为0的数对的个数。 for (int i 0; i < n; i)for (int j 0; j < i; j)if (a[i] …...

【PAT甲级题解记录】1018 Public Bike Management (30 分)

【PAT甲级题解记录】1018 Public Bike Management (30 分) 前言 Problem&#xff1a;1018 Public Bike Management (30 分) Tags&#xff1a;dijkstra最短路径 DFS Difficulty&#xff1a;剧情模式 想流点汗 想流点血 死而无憾 Address&#xff1a;1018 Public Bike Managemen…...

SpringCloud————Eureka概述及单机注册中心搭建

Spring Cloud Eureka是Netflix开发的注册发现组件&#xff0c;本身是一个基于REST的服务。提供注册与发现&#xff0c;同时还提供了负载均衡、故障转移等能力。 Eureka组件的三个角色 服务中心服务提供者服务消费者 Eureka Server&#xff1a;服务器端。提供服务的注册和发现…...

原生django raw() 分页

def change_obj_to_dict(self,temp):dict {}dict["wxh_name"] temp.wxh_namedict["types"] temp.typesdict["subject"] temp.subjectdict["ids"] temp.ids# 虽然产品表里没有替代型号&#xff0c;但是通过sql语句的raw()查询可以…...

Android 9.0 Settings 搜索功能屏蔽某个app

1.概述 在9.0的系统rom产品定制化开发过程中,在系统Settings的开发功能中,最近产品需求要求去掉搜索中屏蔽某个app的搜索,就是根据包名,不让搜索出某个app., 在系统setting中,搜索功能中,根据包名过滤掉某个app的搜索功能,所以需要熟悉系统Settings中的搜索的相关功能,…...

3个关键功能解析:USBToolBox如何简化macOS与Windows的USB端口映射难题

3个关键功能解析&#xff1a;USBToolBox如何简化macOS与Windows的USB端口映射难题 【免费下载链接】tool the USBToolBox tool 项目地址: https://gitcode.com/gh_mirrors/too/tool 在Hackintosh和跨平台开发领域&#xff0c;USB端口映射一直是个令人头疼的技术难题。US…...

STM32单片机学习(28) —— STM32的SPI外设

文章目录概述SPI通信的移位机制&#xff08;以bit为单位&#xff09;SPI外设框图第一部分&#xff1a;数据通路SPI通信的数据帧格式SPI外设移位机制&#xff08;以字节为单位&#xff09;第二部分&#xff1a;主机时钟生成器SPI通信时钟频率与传输速率第三部分&#xff1a;主从…...

ParaView时间戳设置全攻略:从基础标注到自定义格式(5.8.0实测)

ParaView时间戳设置全攻略&#xff1a;从基础标注到自定义格式&#xff08;5.8.0实测&#xff09; 在科学可视化领域&#xff0c;时间戳不仅是数据演变的见证者&#xff0c;更是研究成果呈现的专业语言。ParaView作为开源可视化工具链的标杆&#xff0c;其时间标注功能在学术论…...

如何高效批量下载音乐歌词:智能歌词管理完整指南

如何高效批量下载音乐歌词&#xff1a;智能歌词管理完整指南 【免费下载链接】ZonyLrcToolsX ZonyLrcToolsX 是一个能够方便地下载歌词的小软件。 项目地址: https://gitcode.com/gh_mirrors/zo/ZonyLrcToolsX ZonyLrcToolsX 是一款专业的跨平台歌词下载工具&#xff0c…...

基于双T振荡器的正弦波LED调光电路设计与实践

1. 项目概述&#xff1a;用双T振荡器实现正弦波LED调光最近在捣鼓一些氛围灯项目&#xff0c;总感觉用单片机PWM做的呼吸灯效果有点“硬”&#xff0c;那种线性的明暗变化看久了难免审美疲劳。于是翻出以前模拟电路的老本行&#xff0c;琢磨着能不能用纯硬件的方式&#xff0c;…...

Windows Cleaner深度解析:5大核心模块彻底解决系统空间不足问题

Windows Cleaner深度解析&#xff1a;5大核心模块彻底解决系统空间不足问题 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服&#xff01; 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner Windows Cleaner是一款完全免费开源的…...

用图神经网络做缺陷定位,准确率比传统方法高出30%

在现代软件工程的复杂迷宫中&#xff0c;缺陷定位始终是测试团队面临的核心挑战。想象这样一个场景&#xff1a;一个电商系统在特定压力条件下偶发订单丢失&#xff0c;日志中只留下泛泛的超时错误&#xff0c;问题可能深藏在上百个微服务的调用链、分布式事务的竞态条件或某个…...

C语言(12) 指针的常见操作

指针的常见操作指针变量&#xff0c;有两方面的意思:一个指针指向的内容(数据值&#xff0c;一级)指针变量本身存储的数据 (地址值)#include <stdio.h>int main() {int a 10;int b 0 ;int c 50;int *p NULL;int *q NULL;p &a; // 对指针变量本身进行修改// 对指…...

Claude Agent SDK 从 0 到 1 快速上手教程

Claude Agent SDK 从 0 到 1 快速上手教程 什么是 Claude Agent SDK? Claude Agent SDK 是 Anthropic 官方推出的用于构建 AI 智能体的开发工具包。它基于 Claude Code 构建,让开发者能够以编程方式创建、扩展和定制由 Claude 驱动的应用程序。与简单的聊天机器人不同,基于…...

基于Arduino UNO的真随机数生成与数据持久化在Tambola游戏机中的应用

1. 项目概述&#xff1a;用Arduino UNO打造一台全自动Tambola游戏机如果你玩过或者听说过Tambola&#xff08;在印度非常流行的游戏&#xff0c;在欧美也叫Bingo或Housie&#xff09;&#xff0c;就知道它的核心玩法是主持人从一个装有数字球的容器中随机抽取号码&#xff0c;玩…...