AnalyticDB for PostgreSQL 6.0新特性解析 - OLTP 高并发事务能力优化

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
简介: 本文介绍 ADB PG6.0版本里,面向 OLTP 的高并发执行优化

AnalyticDB for PostgreSQL 4.3版本(以下简称ADBPG 4.3)存在着严重的并发瓶颈,很多操作都需要加互斥排它锁。这导致ADBPG 4.3在高并发情况下,TP 性能不太理想,TPC-C最高只能达到5000 tpmC。AnalyticDB for PostgreSQL 6.0版本(以下简称ADBPG6.0)进行了很多高并发执行优化,解决了很多不必要的锁竞争,极大的提升并发吞吐,将TPC-C的性能提升到了20W+ tpmC,性能相比ADBPG 4.3提升了几十倍。本文详细介绍ADBPG 6.0实现TP性能提升所采用的优化方案,主要包括:全局死锁检测机制、事务优化、表锁的fastpatch机制。

1、全局死锁检测机制

在早期 ADBPG 版本中, 由于没有全局级别的死锁检测,为了避免出现跨分区 segment 的死锁场景, 默认会将 UPDATE/DELETE 所加锁由行锁提升至表锁, 即单表上的 UPDATE/DELETE 只能串行执行. 另外在 PRIMARY KEY/UNIQUE INDEX 存在的场景下, 由纯粹 INSERT 语句组成的事务并发执行时也有可能会导致死锁,故 insert from select 语句也会提升为表锁。

为了解决死锁问题以,并提升高并发 OLTP 能力, ADBPG 在4.3版本 及 6.0版本中均引入了全局死锁检测机制(Global Deallock Detector,以下简称 GDD)。该机制能检测到跨越多个 segment 出现的死锁场景, 并按照一定规则来打破死锁循环. 简单来说, ADBPG 6.0全局死锁检测分为如下几步:

  1. Build lock waits-for graph。GDD 会执行 SELECT * FROM pg_locks 来获取锁等待信息, 之后以 session id 作为图顶点, 遍历扫描锁等待信息. 期间若发现 session A 在等待着 session B 持有着的某个锁, 则认为 A 在等待 B, 此时会在图中建立一个从 A 到 B 的边.
  2. Reduce lock waits-for graph。GDD 会反复遍历第一步建立生成的锁等待图。当发现一个顶点没有出边或者入边, 即表明指定会话没有在等待其他会话, 或者没有其他会话在等待该会话时, 便会将顶点以及关联的边从图中移除. 因为这时可以证明该顶点一定处于一个环中。
  3. Break deadlock cycle。在 Reduce 完成之后, 若 GDD 发现此时锁等待图中不再包含任何顶点, 那么则说明本轮检测没有发现死锁。仍包含有顶点, 那么此时变说明存在死锁情况。此时 GDD 会反复尝试移除具有最大 session 值的顶点, 然后 Reduce 这一步, 直至锁等待图变为空。之后对于被移除的 session, 调用 pg_cancel_backend 来取消这些 session 中 SQL 的执行。

有了GDD后,ADBPG 4.3 和 6.0的UPDATE/DELETE 可以只需要加行锁,而不再需要加表锁,因此单表上的UPDATE/DELETE可以高并发执行,不会因加表锁而阻塞其他该表的并发操作执行。即便出现死锁,GDD可以有效地检测到并且破除死锁。另外,在GDD框架下,ADBPG 6.0对行存表的select for update操作,也不再需要加表锁,而是降级到加行锁。select for update是TPC-C标准测试集的占比较高的SQL语句之一,避免加表锁无疑会大大提升该语句的并发执行能力。

注意:考虑到GDD带来的并发能力的大幅提升,目前ADBPG4.3和6.0版本均已经合入了GDD,以将UPDATE/DELETE的锁从表锁降为行锁。ADB PG 4.3版本的新实例默认引入GDD,UPDATE/DELETE为行锁,但SELECT FOR UPDATE仍然维持着加表锁。 ADB PG 6.0所有实例均引入GDD,且SELECT FOR UPDATE 也为行锁。

2、事务优化

ADBPG 4.3的开始事务(StartTransaction)和结束事务(CommitTransaction)都存在着大量的临界区竞争,针对临界区的加锁行为,严重制约着ADBPG 4.3的并发性能。而ADBPG 4.3在开始事务和结束事务时的加锁行为,是由如下设计逻辑导致的。

2.1、开始事务

分配事务ID。在ADBPG 4.3中,无论是在QD端开始一个分布式事务,还是在QE端开始一个本地事务,ADBPG 4.3都会默认首先去获取一个本地事务ID(xid)。获取xid时,实质是对共享变量进行自增,因此需要持有XidGenLock的排它锁(LW_EXCLUSIVE)。同时,QD端还会去额外获取一个分布式事务ID(gxid),以保证分布式事务的正确执行。同理,获取gxid时,需要持有ProcArrayLock的排它锁。当并发较大时,排它锁的持有会成为性能瓶颈。

分布式事务映射。ADBPG 4.3的事务设计逻辑是分布式事务和本地事务共存:即在执行时,QD会开启一个分布式事务,以保证用户请求在执行时的跨节点强一致性;同时,QD和每个QE还会开始一个本地事务,作为分布式事务在每个节点上的执行单元。这里会存在分布式事务和本地事务的关联映射问题。在ADBPG 4.3中,是通过gxid和xid的映射,来将分布式事务和其对应的各个本地事务关联在一起的。

ADBPG 4.3通过LocalDistribXactData结构体来完成gxid和xid之间的映射,无论在QD上还是在QE上,在每次映射时,都需要从空闲链表上摘掉一个空闲的LocalDistribXactData的实例,将gxid和xid赋给它后,再将它加入到非空闲链表中。由于空闲链表和非空闲链表都是临界资源,对其的操作需要以只有ProcArrayLock的排它锁为前提,相关示例代码如下:

typedef LocalDistribXactData* LocalDistribXact;
LocalDistribXact ele;
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
ele = SharedDoublyLinkedHead_RemoveFirst(&LocalDistribXactShared->sortedLocalBase, &LocalDistribXactShared->freeList);
ele->distribXid = gxid;
ele->localXid = xid;
SharedDoublyLinkedHead_AddLast(&LocalDistribXactShared->sortedLocalBase,&LocalDistribXactShared->sortedLocalList,ele);
LWLockRelease(ProcArrayLock);

同时,每次开启一个事务,QD会从一个全局TMGXACT数组中取一个空闲的项来记录分布式事务的状态。对该全局数组的操作依然需要持有ProcArrayLock的排它锁,相关示例代码如下:

TMGXACT        *gxact;
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
gxact = shmGxactArray[(*shmNumGxacts)++];        
LWLockRelease(ProcArrayLock);

从以上分析可以看出,对ProcArrayLock排它锁的持有,会很大程度上影响高并发下的性能。尤其是ProcArrayLock,其在事务处理的很多阶段(比如事务提交、获取Snapshot等)都会被持有,因此,过多持有其排他锁会带来严重的竞争,限制事务的并发。

2.2、结束事务

由于开始事务时,从全局链表和全局数组中获取了资源,那么在结束事务时,就需要将资源清空后,再返还给全局资源。在将空闲资源插入到全局链表和全局数组中时,牵涉到对全局共享资源的改动,因此,仍然需要持有ProcArrayLock的排它锁来保护相关操作。和开始事务同理,对ProcArrayLock的排它锁的持有,会限制系统的并发性能。

ADBPG6.0对开始事务和结束事务存在的大量加锁行为进行了优化,消除了不必要的临界区竞争,将全局共享资源的操作,改成了私有变量的操作。具体优化逻辑如下。

2.3、事务id延迟分配

ADBPG6.0中,当开始事务时,QD和QE并不会首先去获取一个本地事务ID(xid)。对于一个事务来说,如果该事务只处理读操作而不处理写操作,那么该事务是不需要去获取本地事务ID的。因此,ADBPG6.0将获取本地事务ID的操作,一直推迟到在事务中遇到写操作时才执行,而不是在事务一开始就去获取。如果事务中没有写操作,那么就不会再获取本地事务ID了。

但是QD上仍然会获取一个分布式事务ID(gxid),以确保分布式事务的正确执行。ADBPG6.0对获取分布式事务ID也进行了优化,通过pg_atomic_add_fetch_u32的原子自增操作,来对全局共享变量进行自增和取值,不再需要持有ProcArrayLock的排它锁,提升了事务ID获取的并发性。

2.4、共享资源变为私有变量

对于存在写操作的事务,ADBPG6.0仍然会维护分布式事务ID和本地事务ID的映射。在优化中,ADBPG6.0存储分布式事务ID和本地事务ID映射关系的结构体资源(LocalDistribXactData),不再从全局共享资源中去进行分配和回收,而是各自进程维护自己独立的资源,在进程创建的时候就分配好,在进程结束时就销毁。这种情况下,在进行事务映射时,只需要对自己的私有变量赋值即可,不要再去持有ProcArrayLock。结束事务时,也只需要清空自己私有变量的相关赋值。这种优化消除了临界区的持锁竞争,提升高并发事务下的性能。

同时,QD为了记录分布式事务状态而维护的TMGXACT结构体资源,也不再从全局共享数组去分配和回收,也是每个进程自己在创建的时候就提前分配好资源,在分布式事务创建/提交的时候,对自己的私有变量进行赋值/清空。这也同样避免了对ProcArrayLock的持有申请,提升系统执行的并发性。

2.5、分布式事务优化

ADBPG 4.3的分布式事务也存在着严重瓶颈,主要体现在:如果一个分布式事务的相关操作,只涉及一个segment,那么在该分布式事务提交时,ADBPG 4.3仍然会走两阶段提交,并将其他不相关的segment也涉及进来。两阶段提交是分布式事务性能的“杀手”。 ADBPG6.0对此进行了很好的优化。在分布式事务执行的过程中,ADBPG6.0会记录该事务在执行过程中涉及到的segment。如果整个执行过程中只涉及到一个segment,那么在事务提交时,ADBPG6.0就不再需要走两阶段提交,而是通过一阶段提交即可完成。如果整个执行过程涉及到了多个segment,那么ADBPG6.0只会在这些涉及到的segment上走两阶段提交,不会将无关的segment涉及进来。

3、表锁的fastpatch机制

ADBPG6.0引入了事务优化的一个重大特性 -- 表锁的fastpath机制。ADBPG 4.3没有fastpath机制,对于DML操作SELECT/INSERT/UPDATE/DELETE,在加锁时,需要走到主表的加锁逻辑。这时需要在主表(LockMethodLockHash和LockMethodProcLockHash)中记录加锁信息(LOCK和PROCLOCK),所以要在主表上加上LWLock的排它锁。尽管在主表加锁时,对主表进行了分片,每个分片对应一把排它锁,这样对于不同表的加锁,可能会映射到不同的分片,从而可以减少对主表操作的锁竞争。但是在TP场景下,很多的负载是对同一张表的大并发操作,此时,分片就没有任何效果,所有的并发在加表锁时,都是串行的,严重地影响了TP性能。

Fastpath机制可以有效地减少加锁的开销和大并发下的阻塞问题,从而提高TP的性能。Fastpath适用的场景为DML操作(SELECT/INSERT/UPDATE/DELETE)在加对应表的表锁,对应的锁类型为AccessShareLock、RowShareLock、RowExclusiveLock。ADBPG6.0当前表锁的类型有如下8种:AccessShareLock、RowShareLock、RowExclusiveLock、ShareUpdateExclusiveLock、ShareLock、ShareRowExclusiveLock、ExclusiveLock、AccessExclusiveLock。他们之间的冲突矩阵如下所示(X代表有冲突):

锁类型 AccessShareLock RowShareLock RowExclusiveLock ShareUpdateExclusiveLock ShareLock ShareRowExclusiveLock ExclusiveLock AccessExclusiveLock
AccessShareLock X
RowShareLock X X X
ShareUpdateExclusiveLock X X X X
ShareLock X X X X X
ShareRowExclusiveLock X X X X X X
ExclusiveLock X X X X X X X
AccessExclusiveLock X X X X X X X X

从上面的冲突矩阵中可以看出,AccessShareLock、RowShareLock、RowExclusiveLock这三种类型的锁之间互不冲突,他们对应的操作为SELECT/INSERT/UPDATE/DELETE等DML操作。Fastpath机制利用了这个特点,如果一个表上只会加三类表锁,那么加锁请求可以直接加锁无需判断他们之间是否冲突。在这里我们将这三种类型的锁称为weak relation lock。而对于ShareLock、ShareRowExclusiveLock、ExclusiveLock、AccessExclusiveLock这几种类型的锁,我们称为strong relation lock。

Fastpath实现机制。每个backend在PGPROC结构体之中记录了一定数量(默认16个)的表锁(只能是非共享表的表锁)的加锁情况,当请求的表锁类型为weak lock时,并且通过FastPathStrongRelationLocks判断出当前表没有其它backend持有strong relation lock时,那么此次加锁请求则直接通过fastpath加锁,将加锁信息记录在PGPROC和locallock中,而无需操作主表进行加锁。当请求strong relation lock时,不能使用fastpath进行加锁,并且会将、FastPathStrongRelationLocks对应加锁表的分区计数+1,表示对应表的锁有strong lock,用于其它backend加weak relation lock时来判断当前这个表锁有没有加strong relation lock;然后需要访问其它backend的PGPROC中的fastpath加锁信息,将这些backend在这个表上weak relation lock的加锁信息同步到当前的backend中;最后,走主表加锁逻辑进行加锁。对ShareUpdateExclusiveLock类型的加锁请求,不能走fastpath加锁逻辑,而是直接走主表加锁逻辑,并且无需更新FastPathStrongRelationLocks和同步其它backend的fastpath加锁信息,因为它与weak relation lock不冲突。

从上面fastpath加锁机制来看,对于普通DML的加锁如果走fastpath,首先不需要操作主表减少了单个加锁操作的开销,其次是,如果有大并发存在,由于fastpath操作的数据结果在本地backend的PGPROC之中,因此并发之间基本没有锁竞争,在大并发对同一个表的操作负载下能够显著提高性能。

4. 参数配置

在ADBPG6.0中,需要获取极致的TP性能要对以下参数进行检查:

参数 TP友好型参数值 说明 操作
optimizer off 关闭orca优化器 如果为on, 用户可以在本session内进行设置
gp_enable_global_deadlock_detector on 打开全局死锁检测,去掉表锁 需要重启集群,如果为off,用户需要联系ADBPG值班同学进行设置
resource_scheduler/gp_enable_resqueue_priority off/off 关闭resource queue限制,以便跑出更高的并发,跑正常业务不建议关闭 需要重启集群,如果任意为off,用户需要联系ADBPG值班同学进行设置
rds_enable_custom_plan on 使用新生成计划,避免计划广播 如果为off,用户可以在本sesion内进行设置
random_page_cost 10 如果表某列上建有索引,explain查看计划时没有走index scan,需要设置此参数,来减少随机访问的代价,使得查询走index scan 用户可以在本sesion内进行设置
log_statement none 关闭日志输出,跑正常业务不建议关闭 如果不为none,用户需要联系ADBPG值班同学进行设置
max_prepared_transactions 不建议超过1500 用户可以并发执行的总的事务数 需要重启集群,如果过低,用户需要联系ADBPG值班同学进行设置
rds_max_non_super_conns 不建议超过500 用户总的连接数限制 如果过低,用户需要联系ADBPG值班同学进行设置
相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
目录
相关文章
|
3月前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
560 9
|
5天前
|
机器学习/深度学习 人工智能 JSON
Resume Matcher:增加面试机会!开源AI简历优化工具,一键解析简历和职位描述并优化
Resume Matcher 是一款开源AI简历优化工具,通过解析简历和职位描述,提取关键词并计算文本相似性,帮助求职者优化简历内容,提升通过自动化筛选系统(ATS)的概率,增加面试机会。
63 18
Resume Matcher:增加面试机会!开源AI简历优化工具,一键解析简历和职位描述并优化
|
15天前
|
数据采集 机器学习/深度学习 人工智能
静态长效代理IP利用率瓶颈解析与优化路径
在信息化时代,互联网已深度融入社会各领域,HTTP动态代理IP应用广泛,但静态长效代理IP利用率未达百分百,反映出行业结构性矛盾。优质IP资源稀缺且成本高,全球IPv4地址分配殆尽,高质量IP仅占23%。同时,代理服务管理存在技术瓶颈,如IP池更新慢、质量监控缺失及多协议支持不足。智能调度系统也面临风险预判弱、负载均衡失效等问题。未来需构建分布式IP网络、引入AI智能调度并建立质量认证体系,以提升资源利用率,推动数字经济发展。
30 2
|
2天前
|
弹性计算 运维 安全
优化管理与服务:操作系统控制平台的订阅功能解析
本文介绍了如何通过操作系统控制平台提升系统效率,优化资源利用。首先,通过阿里云官方平台开通服务并安装SysOM组件,体验操作系统控制平台的功能。接着,详细讲解了订阅管理功能,包括创建订阅、查看和管理ECS实例的私有YUM仓库权限。订阅私有YUM仓库能够集中管理软件包版本、提升安全性,并提供灵活的配置选项。最后总结指出,使用阿里云的订阅和私有YUM仓库功能,可以提高系统可靠性和运维效率,确保业务顺畅运行。
|
3月前
|
机器学习/深度学习 人工智能 PyTorch
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
本文探讨了Transformer模型中变长输入序列的优化策略,旨在解决深度学习中常见的计算效率问题。文章首先介绍了批处理变长输入的技术挑战,特别是填充方法导致的资源浪费。随后,提出了多种优化技术,包括动态填充、PyTorch NestedTensors、FlashAttention2和XFormers的memory_efficient_attention。这些技术通过减少冗余计算、优化内存管理和改进计算模式,显著提升了模型的性能。实验结果显示,使用FlashAttention2和无填充策略的组合可以将步骤时间减少至323毫秒,相比未优化版本提升了约2.5倍。
113 3
Transformer模型变长序列优化:解析PyTorch上的FlashAttention2与xFormers
|
3月前
|
前端开发 UED
React 文本区域组件 Textarea:深入解析与优化
本文介绍了 React 中 Textarea 组件的基础用法、常见问题及优化方法,包括状态绑定、初始值设置、样式自定义、性能优化和跨浏览器兼容性处理,并提供了代码案例。
129 8
|
3月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
4月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
144 2
|
8天前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
|
6天前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。

热门文章

最新文章

相关产品

  • 云数据库 RDS PostgreSQL 版