本文分享自华为云社区《【华为云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实时获取这个值。

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

从Purge机制说起,详解GaussDB(for MySQL)的优化策略的更多相关文章

  1. 详解GaussDB(for MySQL)服务:复制策略与可用性分析

    摘要:本文通过介绍GaussDB(for MySQL)读写路径,分析其可用性. 简介 数据持久性和服务可用性是数据库服务的关键特征. 在实践中,通常认为拥有 3 份数据副本,就足以保证持久性. 但是 ...

  2. 大数据学习笔记——Spark工作机制以及API详解

    Spark工作机制以及API详解 本篇文章将会承接上篇关于如何部署Spark分布式集群的博客,会先对RDD编程中常见的API进行一个整理,接着再结合源代码以及注释详细地解读spark的作业提交流程,调 ...

  3. Linux/CentOS 服务安装/卸载,开机启动chkconfig命令详解|如何让MySQL、Apache开机启动?

    chkconfig chkconfig在命令行操作时会经常用到.它可以方便地设置和查询不同运行级上的系统服务.这个可要好好掌握,用熟练之后,就可以轻轻松松的管理好你的启动服务了. 注:谨记chkcon ...

  4. MySQL系列详解八:MySQL多线程复制演示-技术流ken

    前言 Mysql 采用多线程进行复制是从 Mysql 5.6 开始支持的内容,但是 5.6 版本下有缺陷,虽然支持多线程,但是每个数据库只能一个线程,也就是说如果我们只有一个数据库,则主从复制时也只有 ...

  5. 【经验】GaussDB(for MySQL)性能优化 —— 日志的“快递驿站”

    GaussDB(for MySQL)数据库在写入性能上,在业界同类产品中是最好的,这主要得益于GaussDB(for MySQL)在MySQL内核方面的诸多优化.其中有一项从“送快递”得来灵感的优化— ...

  6. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  7. android Handler机制之ThreadLocal详解

    概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Messa ...

  8. Hadoop框架:HDFS读写机制与API详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.读写机制 1.数据写入 客户端访问NameNode请求上传文件: NameNode检查目标文件和目录是否已经存在: NameNode响应客 ...

  9. 详解GaussDB(DWS) explain分布式执行计划

    摘要:本文主要介绍如何详细解读GaussDB(DWS)产生的分布式执行计划,从计划中发现性能调优点. 前言 执行计划(又称解释计划)是数据库执行SQL语句的具体步骤,例如通过索引还是全表扫描访问表中的 ...

  10. bitmap--Bitmap详解与Bitmap的内存优化

    一.Bitmap: Bitmap是Android系统中的图像处理的最重要类之一.用它可以获取图像文件信息,进行图像剪切.旋转.缩放等操作,并可以指定格式保存图像文件. 常用方法: public voi ...

随机推荐

  1. 一文搞懂物联网Modbus通讯协议

    简介: 一般来说,常见的物联网通讯协议众多,如蓝牙.Zigbee.WiFi.ModBus.PROFINET.EtherCAT.蜂窝等.而在众多的物联网通讯协议中,Modbus是当前非常流行的一种通讯协 ...

  2. [FAQ] "cannot refer to unexported name" in Golang ?

    Golang 项目中如果使用了其它模块中找不到的函数.常量等,都会提示 "cannot refer to unexported name". 遇到这种情况,要么是拼写错误了,要么是 ...

  3. WPF 简单判断主线程界面是否卡顿的方法

    本文来告诉大家如何使用简单的代码判断当前的软件的 UI 线程或界面是否卡顿 在后台线程调用如下代码即可用来判断是否卡顿 private static async Task<bool> Ch ...

  4. R2_ES中数据的存储测试

    基本概念:ES(一): 架构及原理 关系数据库 ⇒ 数据库 ⇒ 表 ⇒ 行 ⇒ 列(Columns) Elasticsearch ⇒ 索引(Index) ⇒ 类型(Type) ⇒ 文档(Documen ...

  5. 1.13~1.14&&放假寄

    1.13 3点就放了,手机在机房就能拿到,我为了给手机充会电又多留了一会(事实证明这挺对的) 因为我们是 化微机的班,老师收手机都放在一个箱子里,要有人负责把剩下的手机搬到教室,我走得晚还被当成免费劳 ...

  6. log4j的配置详解

    参考文章:https://www.jianshu.com/p/ccafda45bcea 引入log4j: 在项目中单独使用log4j进行日志的输出: maven依赖: <dependency&g ...

  7. kkfileview搭建指南

    最近公司有个需求,需要在线预览pdf,excel,world文档,pdf浏览器是直接支持预览的,vue也有很多插件支持,但是world文档和excel的方案就非常少了,市面上很多付费的,但是咱一般不舍 ...

  8. windows远程桌面和远程协助有什么区别

    一言以蔽之: windows远程桌面是被动式的,只要你开启了这个功能选项,对方有地址和密码就能使用这台计算机. windows远程协助是主动式的,需要向对方提出协助请求,对方答应后即可登录电脑,协助操 ...

  9. 13-flask博客项目之restful api详解1-概念

    一 传统的开发模式 前后端分类概念 前端只需要独立编写客户端代码,后端也只需要独立编写服务端代码提供数据接口即可前端通过AJAX请求来访问后端的数据接口,将Model展示到View中即可 前后端开发者 ...

  10. 分布式任务调度内的 MySQL 分页查询优化

    作者:vivo 互联网数据库团队- Qiu Xinbo 本文主要通过图示介绍了用主键进行分片查询的过程,介绍了主键分页查询存在SQL性能问题,如何去创建高效的索引去优化主键分页查询的SQL性能问题.对 ...