PolarDB MySQL版通过PolarTrans对高并发OLTP场景进行了优化。PolarTrans的核心技术之一是通过提交时间戳技术CTS来取代传统的基于活跃事务列表方案。本文主要介绍了PolarTrans中CTS技术原理及优势,以及标准场景下的性能测试结果。
版本要求
若要开启全局一致性(高性能模式),PolarDB MySQL版集群版本需为以下版本之一:
8.0.2版本且内核小版本需为8.0.2.2.19及以上。
8.0.1版本且内核小版本需为8.0.1.1.29及以上。
5.7版本且内核小版本需为5.7.1.0.26及以上。
如何确认集群版本,请参见查询版本号。
背景信息
目前主流的开源关系型数据库如MySQL或者PostgreSQL,其事务状态更新以及MVCC机制均是采用了基于活跃事务列表的方案。这种方案在高并发场景下会带来严重的性能瓶颈,无法充分利用CPU多核并发处理事务的逻辑;其次,基于活跃事务列表方案在集群一致性读、集群多点写入以及Share-Nothing架构中的XA事务管理上存在天然的缺陷。
在PolarTrans中,事务状态更新无需维护活跃事务列表,传统的事务状态的拷贝过程通过获取当前集群的最大提交时间戳来替代。事务状态的迭代、获取、查询(可见性判断)等逻辑更加轻量化,同时PolarTrans将大部分的事务逻辑进行无锁优化,对于读写混合场景、纯写场景都有较大性能提升。
PolarTrans CTS技术的核心数据结构为CTS log,事务状态迭代、可见性判断、事务活跃状态等核心事务逻辑,都是通过CTS log来完成的。CTS log的数据结构如下图所示:
全内存设计的CTS log由一段ring buffer
组成,事务通过trx_id
取模映射到其对应的slot
,每个slot
包含trx
指针和csn(事务提交序列号)。
技术优势
写事务启动
原生事务系统在写事务启动时,需要通过
trx sys mutex
保护来分配事务ID,写入活跃事务ID数组(rw_trx_ids
),维护活跃事务ID到trx
映射的集合(rw_trx_set
),以及读写事务链表(rw_trx_list
)等数据结构。在PolarTrans事务系统中,事务启动时会注册到CTS log,根据trx_id
取模分配相应的slot
,并将事务状态设置为特殊的active标记即可,并且该过程可以做到无锁化处理。写事务提交
原生事务系统写事务提交时,需要在
trx sys mutex
保护下, 查找rw_trx_ids
并移除对应的trx_id
,维护rw_trx_set
、rw_trx_list
等。在PolarTrans事务系统中,事务提交时分配提交时间戳并更新CTS log中对应的csn字段即可。read view
InnoDB的MVCC机制核心需要通过
read view
来控制数据的可见性,原生事务系统获取read view
的过程同样需要在trx sys mutex
保护下,拷贝活跃事务ID数组、当前最小活跃ID和最大事务ID。在进行可见性判断时, 可能需要查找活跃事务ID数组来确定可见性。在读写冲突较为严重的场景下,读写事务和只读事务都需要在mutex
保护下更新和拷贝当前事务状态,维护代价极高,并且可见性判断效率较低。在PolarTrans事务系统中,通过获取事务系统的最大提交时间戳来代替原生read view
,同样可以做到无锁处理。在可见性判断过程中, 您只需要对比只读事务csn和行记录的trx csn
即可。
开启PolarTrans
全局一致性(高性能模式)功能开启后,PolarTrans功能会默认打开。关于如何开启全局一致性(高性能模式)功能,请参见如何开启全局一致性(高性能模式)。
性能对比
在相同场景下,分别测试原生事务系统(关闭PolarTrans)和PolarTrans事务系统(开启PolarTrans)的QPS。
测试环境
一个规格为88核710 GB的PolarDB MySQL版8.0版本集群版。
测试工具
Sysbench
测试数据量
88张表,每张表1200万条记录。
测试用例
使用以下Sysbench内置用例进行测试。
oltp_read_write
oltp_insert
oltp_update_index
oltp_update_no_index
oltp_read_only
测试结果及说明
从以下测试中可以看出,在读写或只写场景下,PolarTrans事务系统对于数据库整体性能有非常大的提升。在只读场景下,整个数据库的性能并没有发生变化,只读事务可以通过ReadView缓存来降低事务状态拷贝过程中的加锁开销,所以PolarTrans事务系统相比原生事务系统并不会带来明显的性能提升。
oltp_read_write
oltp_insert
oltp_update_index
oltp_update_no_index
oltp_read_only