- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
本文分享自华为云社区《【华为云MySQL技术专栏】GaussDB(for MySQL) Purge优化》,作者:GaussDB 数据库.
在MySQL中,尤其是在使用InnoDB引擎时,Purge机制至关重要。它可以回收undo log【1】,清理过期数据,减少磁盘占用,维护数据库的整洁与高效.
MySQL InnoDB引擎使用undo log来保存事务修改记录的历史信息。事务提交后, update undo log(指在delete和update操作中产生的回滚日志)未被立即删除,而是会被记录到undo history list【2】,等待Purge线程进行最后的删除。当undo log不再被任何事务依赖时,系统就会扫描这个undo log,将过期的索引数据删除并清理undo log本身,这个整体的清理过程就是MySQL InnoDB引擎的Purge机制.
根据undo log header中的信息判断这些事务是否存在过期数据,如果判断存在过期数据,就要触发Purge机制进行清理,否则就不需要.
其过程主要包括:扫描undo 页面来获取undo记录,遍历undo记录以确认是否要进行清理,如果需要则删除索引中的过期数据.
purge的速度会影响已提交的undo log的清理回收,如果purge的清理速度赶不上事务生成undo log的速度,undo log就会出现堆积。如果条件允许的话,对undo tablespace进行truncate(截断)来实现undo空间的回收.
undo log和索引都有历史版本数据,undo log未及时清理会导致undo log自身以及undo关联的过期索引数据产生堆积,占用额外的存储空间,容易引起不必要的扩容和开销,对客户业务而言是不利的.
undo log堆积会导致过期索引数据堆积,索引页面中会存在大量已经标记为delete的数据,这时候每个索引页面实际的有效数据占比就会很低,业务SQL执行中会出现获取少量数据却需要进行大量页面IO的情况,最终导致SQL执行性能劣化.
当前undo堆积已经成为数据库运行的一个痛点问题,因此华为云GaussDB(for MySQL)团队专门针对Purge机制存在的问题进行了如下优化.
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倍提升.
我们发现当前在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相关的线程均为后台常驻线程,对于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.
实例规格: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速度对比 。
实例规格: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(forMySQL)的优化策略的文章就讲到这里了,如果你想了解更多关于从Purge机制说起,详解GaussDB(forMySQL)的优化策略的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
作者:小林coding 计算机八股文网站:https://xiaolincoding.com 大家好,我是小林。 今天跟大家聊聊,常见的缓存更新策略。 Cache Aside(旁路缓存)策略; Rea
我使用 git 多年,最近为了一个项目改用 mercurial。在过去的 6 个月里,我已经学会了如何通过命令行很好地使用 Mercurial。 这可能是我的想象,但在我看来,mercurial 在
这个问题适合任何熟悉的人 Node.js express Passport 带有 Passport 的 JWT 身份验证(JSON Web token ) Facebook OAuth2.0 或谷歌
在 Coq 中,当试图证明记录的相等性时,是否有一种策略可以将其分解为所有字段的相等性?例如, Record R := {x:nat;y:nat}. Variables a b c d : nat.
我正在处理的项目目前只有一个 Bootstrap 文件,用于初始化应用程序中的所有 javascript 对象。类似于下面的代码 if(document.getElementById('nav'))
我正在考虑使用 OpenLDAP 在首次登录时添加密码到期和强制更改密码。 似乎使用 ppolicy 覆盖来实现这一点。 当我在 ppolicy.schema 中看到这个时,我开始使用 ppolicy
这基本上是我昨天问的一个问题的重新陈述,因为我得到的一个答案似乎没有理解我的问题,所以我一定是不清楚。我的错。 因为 WPF 依赖于 DirectX,所以它对卡和驱动程序的内部非常敏感。我有一个案例,
我是单点登录(SSO)概念的新手。我开始知道 SAML 请求和响应是实现 SSO 流程的最佳方式。然后我开始阅读有关 SAML2.0 的信息。我来了一个术语 NameIdPolicy 在 saml1.
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 5年前关闭。 Improve this questi
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
在 Azure 上创建新的 SQL 数据库时,它将“计算+存储”选项设置为“2 vCore + 32GB 数据最大大小”作为默认配置,但我不想使用 vCore,我可以更改它。但问题是,是否可以通过策略
我希望创建一项策略,防止在未启用身份验证的情况下创建应用服务(仅审核它们是不够的)。 以下策略可以正确识别未启用身份验证的现有资源: { "mode": "All", "policyRule"
我正在尝试从现有 AuditIfNotExists 策略创建 DeployIfNotExists 策略。部署时不会出错,但会错误提示“没有相关资源与策略定义中的效果详细信息匹配”。当评估政策时。当我将
我正在尝试从现有 AuditIfNotExists 策略创建 DeployIfNotExists 策略。部署时不会出错,但会错误提示“没有相关资源与策略定义中的效果详细信息匹配”。当评估政策时。当我将
我正在使用 wunderground 的 json api 来查询我网站上的天气状况。 api 为我提供了一个包含所有必要数据的漂亮 json 对象,但我每天只能进行多次调用。存储这些数据的首选方式是
我有一个名为可视化数据结构的项目。我有这样的 OOP 设计。 Class VisualDataStructures extends JFrame Class ControlPanel extends
这个问题在这里已经有了答案: 关闭 14 年前。 副本: Use javascript to inject script references as needed? Javascript 没有任何指
Android 应用程序遇到了一些 ANR 问题,因此我实现了 StrictMode 策略。以前从未使用过这个,所以希望有人可以帮助解释以下内容: 为什么日志显示 2 个看似相似的违规行为,除了前 4
我目前正在尝试解决一个问题。假设我们在路上行驶,我们知道路上有 10 家酒店。每家酒店都有 0 到 6 星。我的问题是:找到选择星级酒店的最佳解决方案。唯一的问题是:您不能回头去参观您已经决定不去的酒
我正在将我的应用程序迁移到 MVP。从这个 konmik 中获得了有关静态演示者模式的提示 这是我的简要 MVP 策略。为简洁起见,删除了大部分样板和 MVP 监听器。这个策略帮助我改变了方向,证明了
我是一名优秀的程序员,十分优秀!