当前位置:网站首页>Postgresql snapshot optimization Globalvis new system analysis (performance greatly enhanced)
Postgresql snapshot optimization Globalvis new system analysis (performance greatly enhanced)
2022-08-03 19:05:00 【mingjie】
相关: 《Postgresql源码(18)PGPROC相关结构》《Postgresql快照优化Globalvis新体系分析(性能大幅增强)》《Improving Postgres Connection Scalability: Snapshots》
PG的新快照体系Globalvis分析
- 本篇介绍快照优化作者Andres Freund的优化总结文章.
- 本篇中有很多个人理解,不一定准确,推荐阅读:《Improving Postgres Connection Scalability: Snapshots》.
- 本篇文章作为新版本PG快照分析的第一篇,后面几篇新代码再做展开分析.
先看下这个优化的性能提升效果,在高连接数下会有明显提升:
一、概念回顾
1 MVCC
- 传统锁机制无法做到读、写的并发操作,因为数据只有一个版本.引入mvcc后,数据存在多版本,可以做到读一个版本、写另一个版本,实现读写并发.
- 如果实现这样机制,需要每个行版本记录xmin(可见开始位点visible since),xmax(可见结束位点visible until).
- 位点即时间戳,PG中使用自增正整数表示.
2 快照
- 只有时间戳还是不够的,决定我当前能否看到一个元组,我还必须知道创建、删除元组的时间戳所代表的事务是否已经提交了.为了避免脏读,只有提交的事务才会被看做已生效.
- PG使用快照来记录哪些事务正在运行中.
- PG的SnapshotData结构中,xip记录了所有运行中的事务ID.
typedef struct SnapshotData
{
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[] */
...
3 快照获取
优化之前PG是如何获取快照的?
- 每个PG进程都对应一个PGPROC结构、一个PGXACT结构(PG14把PGXACT合到PGPROC里面了)
- PGPROC数组在初始化的时候就全部申请好了,再找PROC的时候为了避免每次都遍历整个数组,在
procArray->pgprocnos
柔性数组中记录了排序过后的PGPROC数组的索引,参考这篇:《Postgresql源码(18)PGPROC相关结构》. - 在构建快照时,GetSnapshotData会遍历
procArray->pgprocnos
找到所有存在的PGPROC、PGXACT结构,收集所有的xid. - 在构建快照时,还有一些细节:
- 为了方便,GetSnapshotData会计算全局最久
PGXACT->xmin
,用于在访问的过程中做一些vacuum的事情,回收元组. - 为了实现savepoint,一个backend需要记录多个事务ID.
- 为了效率,vacuum忽略一些执行中的backend.
- 备机上的快照计算完全不同(以前做过分析,文章写得很简陋,后面再补一篇)
- 为了方便,GetSnapshotData会计算全局最久
4 历史优化
2011年已经发现GetSnapshotData存在瓶颈,当时做的优化是把PGPROC里面把快照需要的变量拆出来,放到PGXACT中,这样数据结构小很多,可以装到一个cpu cache line中.
二、识别当前的瓶颈点
从上述分析中可以看出,遍历所有连接的复杂度为O(#connection)
,快照计算成本随连接数线性增加.
理论上有两种提高扩展性的方法:
- 寻找复杂度更低的算法,避免
O(n)
. - 对每个连接做更少的操作,减少单次操作的时间.
旧版本的快照获取步骤:
xmin = global_xmin = inferred_maximum_possible;
for (i = 0; i < #connections; i++)
{
int procno = shared_memory->connection_offsets[i];
PGXACT *pgxact = shared_memory->all_connections[procno];
// compute global xmin minimum
// 记录全局做小xmin
if (pgxact->xmin && pgxact->xmin < global_xmin)
global_xmin = pgxact->xmin;
// nothing to do if backend has transaction id assigned
// 未启动事务直接跳过
if (!pgxact->xid)
continue;
// the global xmin minimum also needs to include assigned transaction ids
// 全局最小xmin也要包含最小的事务ID
if (pxact->xid < global_xmin)
global_xmin = pgxact->xid;
// add the xid to the snapshot
// 活跃事务记录到快照的xip中
snapshot->xip[snapshot->xcnt++] = pgxact->xid;
// compute minimum xid in snapshot
// 记录最小的xid到快照中
if (pgxact->xid < xmin)
xmin = pgxact->xid;
}
snapshot->xmin = xmin;
// store snapshot xmin unless we already have built other snapshots
if (!MyPgXact->xmin)
MyPgXact->xmin = xmin;
RecentGlobalXminHorizon = global_xmin;
这里最重要的一点:
- 循环体起始只需要计算活跃事务就好了,但是,这里还顺便计算了全局xmin.这不是快照的一部分,但可以方便的同时计算,只需要很小的代价(or so we thought…).
- 代码作者花了很长时间,试图去理解为什么遍历几千个元素,要话费如此昂贵的代价.
针对瓶颈点,作者做了三层优化.
1 瓶颈点&优化:ping pong
问题主要来自于这行代码(这里的MyPgXact->xmin
的含义是:最小的运行中的xid,不包括lazy vacuum)
xmin = global_xmin = inferred_maximum_possible;
for (i = 0; i < #connections; i++)
{
...
...
if (!TransactionIdIsValid(MyPgXact->xmin))
MyPgXact->xmin = TransactionXmin = xmin; <---------------- 这里
...
}
因为这个值要记录运行中的最小xid,所以连接的事务提交、终止都需要更新这个值,在正常运行的系统中,由于xid是不断推进的,这个值的更新频率非常高.
在当前最常见的CPU微架构中,每个核心私有L1和L2缓存,每个CPU插槽上所有核共享L3缓存.
- 第一点:假设有8核的CPU,8个连接在并发的构建8个快照,每个连接都需要读取他的七个PGXACT,然后修改自己的PGXACT;这时读取的其他七个PGXACT也在被不停的修改中,这样读取的PGXACT就会经常失效了.可能刚刚缓存好,别人把xmin修改了导致缓存的PGXACT失效,需要从内存重新拿上来.
- 第二点:xmin其实是不需要访问的,需要的是计算出一个全局最小xid.但是不访问xmin也没什么用,因为xmin和xid在一个cache line上,xmin虽然不访问,但是会修改. 改了就会让整个cache line失效,导致xid的访问也很慢.
关于第二点:
代码作者优化掉了RecentGlobalXminHorizon(用于清理死元组),引入了两个没那么准确的新值:
- A:确定比A小的都已经可以清理了
- B:确定比B大的都无法清理
在A、B中间的元组会引入昂贵的准确计算,避免在GetSnapshotData中计算引发上述问题.
2 瓶颈点&优化:数据离散访问
PGXACT的存放位置是离散的,可能在allPgXact大数组中的任意几个位置,不连续.(参考《Postgresql源码(18)PGPROC相关结构》)在使用时,通过连续的pgprocnos数组中记录的index找到活跃的PGXACT.
GetSnapshotData
...
//优化前,通过pgprocnos拿到索引,通过索引在离散的allPgXact数组中拿到xid
numProcs = arrayP->numProcs;
for (index = 0; index < numProcs; index++)
{
int pgprocno = pgprocnos[index];
volatile PGXACT *pgxact = &allPgXact[pgprocno];
...
//优化后,在密集数组other_xids中拿xid
for (int pgxactoff = 0; pgxactoff < numProcs; pgxactoff++)
{
TransactionId xid = UINT32_ACCESS_ONCE(other_xids[pgxactoff]);
问题就是数据是离散的,将xids单独拿出来放到连续存储的密集数组中,可以显著提高命中率.
3 瓶颈点&优化:快照缓存
- 经过上面两个优化(都在优化O(n)中的n),在连接数很高时计算一个快照仍然是一个昂贵的操作.
- 经过上面优化后,快照中不在维护RecentGlobalXmin,这样就可以做一个更大的改进:如果我们可以确定快照没变,就不用重新计算了.以前这是不可行的,因为RecentGlobalXmin比快照本身的更新频率要高很多.
- 快照唯一需要更新的时机是:之前运行的一个事务提交了.(快照最根本的功能是提供运行事务id列表,列表中最大的那个就是xmax了,事务提交后就相当于不在运行事务列表中了,在做可见性判断时如果不在运行事务列表中,就知道事务已经提交或回滚了,这就需要继续走标志位 或 clog判断了;但是如果事务ID在运行事务列表中,那就一定没提交,不需要做任何进一步判断)
- 因此,作者设计了一个xactCompletion内存计数器,记录提交或终止的事务数量.
- 当要求重新计算快照时,我们检查计数器,如果没变可以直接复用上一个快照.
- 如果计数器变了,那么需要重新计算快照.
边栏推荐
- [Azure Event Hub] Create Event Hub Consume Client + Custom Event Position with Azure AD Authentication
- 力扣刷题之合并两个有序数组
- How does MySQL permanently support Chinese input once and for all?
- 要想成为黑客,离不开这十大基础知识
- MySQL【变量、流程控制与游标】
- 基于DMS的数仓智能运维服务,知多少?
- POJ 3041 Asteroids(最大匹配数=最小点覆盖)
- 【C语言学习笔记(六)】分支与跳转(if、else、continue、break、switch)
- 【WPS-OFFICE-Word】 WPS中样式的运作原理?样式自动更新、自动改变如何处理?样式的管理方法?
- MD5是对称加密还是非对称加密,有什么优缺点
猜你喜欢
Compose原理-compose中是如何实现事件分法的
使用安全浏览器将网页保存为pdf的方法步骤
LineSegmentTree线段树
图像超分——Real-ESRGAN快速上手
YAML中多行字符串的配置方法:|+、 |、 |-、 >+、 >、 >-的区别
字节跳动三面拿offer:网络+IO+redis+JVM+GC+红黑树+数据结构,助你快速进大厂!!
安装radondb mysql遇到问题
WEB 渗透之CSRF
MySQL超详细安装教程 手把手教你安装MySQL到使用MySQL 最简单的MySQL安装方式,这种方式装,卸载也简单
丙二醇二乙酸酯(Propylene Glycol Diacetate)
随机推荐
基于DMS的数仓智能运维服务,知多少?
Web项目Controller统一返回实体类
MD5是对称加密还是非对称加密,有什么优缺点
力扣刷题之合并两个有序数组
Solution for no navigation bar after Word is saved as PDF
Bytes to beat three sides take offer: network + GC + + IO + redis + JVM red-black tree + data structure, to help you quickly into the giant!!!!!
梅科尔工作室-14天华为培训七
Confused!Ali was abused on the one hand, but was fortunate to be promoted to Huawei's technology, and successfully got the offer, with an annual salary of 40w
普通用户如何利用小红书赚钱呢?小红书的流量是真的吗?
【夜莺监控方案】08-监控msyql集群(prometheuse+n9e+mysqld_exporter)
系统太多,多账号互通如何实现?
vulnhub pyexp: 1
POJ 1465 Multiple(用BFS求能组成的n的最小倍数)
MySQL详细学习教程(建议收藏)
ADS 2023 下载链接
MySQL如何一劳永逸的永久支持输入中文
mysql跨库关联查询(dblink)
不要小看 WebSocket!长连接、有状态、双向、全双工都是王炸技能
[Dataset][VOC] Rat dataset voc format 3001 sheets
Postgresql源码(65)新快照体系Globalvis工作原理分析