从Purge机制说起,详解GaussDB(for MySQL)的优化策略

本文分享自华为云社区《【华为云MySQL技术专栏】GaussDB(for MySQL) Purge优化》,作者:GaussDB 数据库。

在MySQL中,尤其是在使用InnoDB引擎时,Purge机制至关重要。它可以回收undo log【1】,清理过期数据,减少磁盘占用,维护数据库的整洁与高效。

Purge机制

MySQL InnoDB引擎使用undo log来保存事务修改记录的历史信息。事务提交后, update undo log(指在delete和update操作中产生的回滚日志)未被立即删除,而是会被记录到undo history list【2】,等待Purge线程进行最后的删除。当undo log不再被任何事务依赖时,系统就会扫描这个undo log,将过期的索引数据删除并清理undo log本身,这个整体的清理过程就是MySQL InnoDB引擎的Purge机制。
Purge的操作可以分成三个主要步骤:

1.遍历已经提交的update undo log

根据undo log header中的信息判断这些事务是否存在过期数据,如果判断存在过期数据,就要触发Purge机制进行清理,否则就不需要。

2.通过undo log进行数据的物理删除

其过程主要包括:扫描undo 页面来获取undo记录,遍历undo记录以确认是否要进行清理,如果需要则删除索引中的过期数据。

3.回收undo log

purge的速度会影响已提交的undo log的清理回收,如果purge的清理速度赶不上事务生成undo log的速度,undo log就会出现堆积。如果条件允许的话,对undo tablespace进行truncate(截断)来实现undo空间的回收。
undo log堆积主要会产生两方面的影响:

第一, 额外的存储占用

undo log和索引都有历史版本数据,undo log未及时清理会导致undo log自身以及undo关联的过期索引数据产生堆积,占用额外的存储空间,容易引起不必要的扩容和开销,对客户业务而言是不利的。

第二,性能下降

undo log堆积会导致过期索引数据堆积,索引页面中会存在大量已经标记为delete的数据,这时候每个索引页面实际的有效数据占比就会很低,业务SQL执行中会出现获取少量数据却需要进行大量页面IO的情况,最终导致SQL执行性能劣化。

Purge优化实现

当前undo堆积已经成为数据库运行的一个痛点问题,因此华为云GaussDB(for MySQL)团队专门针对Purge机制存在的问题进行了如下优化。

优化点一:coordinator 与 worker流水线化

Purge任务是由Purge线程完成的,是InnoDB的常驻线程。其线程主要分成两个角色,分别是一个purge coordinator线程和若干个purge worker线程,以下简称为coordinator和worker。

事务的修改可能会残留过期数据在索引中,而老数据的相关信息又存留在undo记录中,事务提交时的undo log会被记录在回滚段的History List中,coordinator负责从History List中获取undo log,读取其中的undo记录,并将可能残留过期数据的undo记录分发给worker来进行处理。所以,当前purge的流程可以简单划分成以下两个阶段:
阶段一:coordinator读取undo log包含的undo页面,获取undo记录。

阶段二:coordinator将读取到的undo记录批量分发给worker来进行处理,线程之间并发执行,且coordinator也会负责一部分undo记录的处理,待coordinator和所有worker都执行完毕后开启下一轮处理。

图1 purge原生流程

图1所示为原本的Purge流程,阶段一coordinator是单线程执行,阶段二worker是多线程并发,即并行执行,但整体两个阶段是串行执行,即阶段一执行完,阶段二才会继续执行。如果阶段一存在大量undo 页面都需要进行IO,串行执行就会严重影响整体的执行效率。不过,这种两阶段串行化执行的方式是可以优化的。

优化的整体思想即是:将coordinator和worker的执行流水线化。从图1可以看到,在原生Purge流程中,coordinator除了负责扫描获取undo记录的任务,本身也会承担一部分Purge任务,且必须同步等待所有已分发的Purge任务完成之后,才能开始下一批次的undo记录扫描任务,这样就导致阶段一和阶段二是一个串行过程。

若令coordinator只单一地负责undo记录的扫描,不再兼职Purge清理任务,这样在worker执行的过程中,coordinator就能直接继续去获取undo记录, 不再需要同步等待所有的Purge任务完成,这样就可以达到将原本串行的两阶段执行变成流水线执行的目的。

图2 purge优化流程

图2为优化后的Purge流程,Purge优化会先将innodb_purge_batch_size指定的undo页面拆成若干个小的batch, 拆分的批次数量由innodb_rds_purge_subbatch_size决定。coodinator会先扫描第一个小batch的undo 记录,然后分发给各个worker并行处理,在worker处理过程中,coordinator可以去扫描第二个小batch的undo记录,等到所有worker执行完第一批purge任务后,coordinator将立即分发第二批undo记录,worker继续并行执行,而coordinator则立即开始并行地解析第三个小batch的undo记录,以此类推。

  • 优化效果评估

当coordinator获取完第一个小batch之后,后续coordinator和worker都是同时运行的,每个batch运行的时间由coordinator和worker运行时间较长者决定,为了避免不必要的线程间等待,需要通过调整参数来令两个线程的耗时接近。

目前通过开启innodb_monitor_enable的module_purge监控,观察coordinator的耗时以及worker的耗时,再通过调整innodb_purge_batch_size和innodb_rds_purge_subbatch_size参数,将coordinator和worker的耗时调整到接近,让每个batch整体耗时降低。当前测试结果,innodb_purge_batch_size(600),innodb_rds_purge_subbatch_size(150)为最优配置,在此配置下purge速度有1倍提升。

优化点二:undo记录二次分发

我们发现当前在Purge过程中,coordinator分发undo记录给worker的策略是基于InnoDB层的table id,即对于同一个表的undo记录都会分发给一个worker。

这就会出现一种场景:当单个热点表被频繁执行DML时,会生成大量基于这个表的undo记录,此时无论innodb_purge_threads值设置多大,Purge的任务都只会由一个线程承担,Purge机制由原本设计上的并发执行回退成单线程执行,Purge效率降低。

针对这个问题,我们在保持基于table id分发逻辑的基础上,增加一轮二次分发机制。

  • 整体思路

01 根据Purge线程数将undo记录进行分组(如图3),Purge线程数量为4,因此将undo记录划分为四个分组。

02 第一次分发(基于table id分发):将获取出来的undo记录根据table id进行分配,如果当前分组已存在该table id对应的undo记录,则继续分配至该分组;如果不存在包含该table_id的undo记录的分组,则寻找一个容量最小的分组,然后分配给小容量分组。

03 检测当前分配是否均衡,确认当前是否每个分组的记录数都小于max_n= (m_total_rec + n_purge_threads - 1) / n_purge_threads。

如果是大于max_n则说明当前分组过载,否则就认为是均衡的。如图3中,max_n = (11+4 - 1) / 4 = 3,因此第二个、第四个分组均过载,需要进行二次分发。

04 第二次分发(基于分组负载分发):如果当前分组过载,则将过载部分数据转移至相邻下一个分组,然后校验下一个分组是否过载,循环校验,最多遍历2次所有分组。图4中,最终每个分组的记录数不超过3条,相同table id的undo记录也会分发到不同分组,例如rec3和rec4属于相同的table,经过二次分发最终会分发到不同的分组,但是分发到不同分组对应最后的Purge结果并不影响。
图3 二次分发

图4 最终分发结果

优化点三:Purge线程优先级调整

考虑到Purge相关的线程均为后台常驻线程,对于GaussDB(for MySQL)而言,有较多后台线程,因此本身Purge相关线程的调度不处于高优先级,Purge线程不会被系统频繁调度。所以,第三个优化点是调整Purge相关线程的优先级,GaussDB(for MySQL)将以高优先级启动Purge线程,确保Purge任务能够及时被调度。

测试验证

预备条件

innodb_rds_fast_purge_enabled: 以上三个优化开启的特性开关,开启后特性全部生效。

innodb_purge_batch_size :单个大batch处理的undo页面数,设置为600,一个大batch会被划分成多个小batch。

innodb_rds_purge_subbatch_size:单个小batch处理的undo页面数,设置为150。

测试模型一:验证空载场景下Purge速度

  • 实例规格:8U32G

  • 数据库版本:GaussDB(for MySQL)-2.0.51.240300

  • 操作系统:EulerOS 2.0(SPS)

  • 数据量:64 张sysbench宽表,单表1000万行数据

  • 并发数: 1/4/8/16/32/64/128/256/512 线程并发,读写模型

  • 数据文件 :为了精确对比purge速度提升效果,我们对比空载场景即无业务负载。使用history length已经达到5亿的数据文件,在空载场景下对比开启优化和未开启优化的清理速度。

实际开启优化后,空载Purge清理速度大约有1倍提升,具体结果展示如下:

图5 purge速度对比

测试模型二:验证特性开启后对SQL执行性能的影响

  • 实例规格:8U32G

  • 数据库版本:GaussDB(for MySQL)-2.0.51.240300

  • 操作系统:EulerOS 2.0(SPS)

  • 数据量:64 张sysbench宽表,单表1000万行数据

  • 并发数: 1/4/8/16/32/64/128/256/512 线程并发,读写模型

开启和关闭开关后,执行sysbench不同并发下的性能表现如下,开启关闭优化特性后,QPS基本持平,说明优化特性对于业务性能基本可以忽略。

图6 性能对比

总结

Purge机制负责GaussDB(for MySQL) InnoDB过期数据的清理,对于数据库高性能平稳运行起到至关重要的作用。Purge机制不及时不仅会导致过期数据的堆积,占用大量磁盘空间,还会影响SQL执行效率。当前GaussDB(for MySQL)的Purge优化功能,通过任务流水线化、线程优先级调整、二次分发等手段,避免数据库undo log堆积,极大提升Purge的性能,大幅改善用户体验。

相关概念

【1】Undo Log:即回滚日志,保存了记录修改前的数据。在InnoDB存储引擎中,undo log分为insert undo log和update undo log。

insert undo log是指在insert操作中产生的undo log。由于insert操作的记录,只是对本事务可见,其它事务不可见,所以undo log可以在事务提交后直接删除,而不需要额外操作。

update undo log是指在delete和update操作中产生的undo log。该undo log可能要用于多版本并发控制的老版本数据获取,因此不能在提交的时候删除。

【2】Undo History List:即记录所有已提交事务的undo log的链表,可以通过该链表找到所有未被清理的已提交事务关联的undo log。事务提交时,insert undo log会被回收掉(reused或者free), update undo log则会被移动到Undo History List链表。因此Undo History List的长度即History Length反应了未被处理和回收的update undo log的数量,我们一般通过History Length来评估undo log堆积的情况,可以通过 show engine innodb status实时获取这个值。

点击关注,第一时间了解华为云新鲜技术~

相关推荐
XYiFfang7 小时前
【MYSQL】SQL学习指南:从常见错误到高级函数与正则表达式
sql·mysql·正则表达式·regexp_like·group_concat
十碗饭吃不饱9 小时前
sql报错:java.sql.SQLSyntaxErrorException: Unknown column ‘as0‘ in ‘where clause‘
java·数据库·sql
呆呆小金人10 小时前
SQL入门: HAVING用法全解析
大数据·数据库·数据仓库·sql·数据库开发·etl·etl工程师
l1t15 小时前
用parser_tools插件来解析SQL语句
数据库·sql·插件·duckdb
TDengine (老段)15 小时前
TDengine 数学函数 ABS() 用户手册
大数据·数据库·sql·物联网·时序数据库·tdengine·涛思数据
Hello.Reader18 小时前
Apache StreamPark 快速上手从一键安装到跑起第一个 Flink SQL 任务
sql·flink·apache
养生技术人1 天前
Oracle OCP认证考试题目详解082系列第57题
运维·数据库·sql·oracle·开闭原则
养生技术人1 天前
Oracle OCP认证考试题目详解082系列第53题
数据库·sql·oracle·database·开闭原则·ocp
豆沙沙包?1 天前
2025年--Lc171--H175 .组合两个表(SQL)
数据库·sql
养生技术人2 天前
Oracle OCP认证考试题目详解082系列第48题
运维·数据库·sql·oracle·database·开闭原则·ocp