简介: 近几年,随着分布式数据库系统的衰亡,特地是基于MySQL分布式数据库系统,会用到XA来保障全局事务的一致性。家喻户晓,MySQL对XA事务的反对是比拟弱的,存在很多问题。为了满足分布式数据库系统对XA事务的要求,阿里做了大量的工作。 本篇内容将从两局部介绍,第一局部介绍在AliSQL分支上做的一些实用功能;第二局部介绍XA Crash Safe问题的本源和在5.7和8.0版本上的实现原理。
一、阿里云RDS MySQL(AliSQL)
AliSQL是MySQL的分支,阿里在这个分支上做了很多深度的定制,以充沛开掘MySQL的后劲。AliSQL撑持了阿里团体电商业务十余年,其稳定性、安全性和高性能是通过了极其严苛实际测验的。除此之外,AliSQL做了很多实用性的性能,以进步MySQL的易用性和应用效率。下图是AliSQL上重要的性能的列表。
二、RDS定制化性能介绍
1. 实用性:SQL Outline 在线固化SQL执行打算
咱们应用MySQL的时候时常会碰到一种状况,即业务跑着的时候有个SQL执行会变慢,剖析之后发现是这个SQL执行打算产生了变动。这种变动有很多起因,比方bug或是版本升级了等等。
MySQL就提供了hint性能,它能够使咱们在SQL语句里减少一些提醒,以保障SQL在生成执行打算的时候是依照提醒来工作的。但这只是比拟理想化的状态,理论状况中这样是很不不便的,因为业务曾经在线上运行了,这个时候即便可能扭转业务的SQL,也须要一个很漫长的工夫和过程。
为了解决这个问题,就有了SQL Outline的性能。这个性能不须要扭转利用的SQL语句,只须要在server端通知RDS碰到哪种类型的特定的SQL,能够给它定制一个hint,而后依照用户指定的形式执行。
2. 实用性:Performance Agent可诊断、可度量
咱们在实例的监控上也做了大量的工作,从而能够很容易的剖析数据库中的一些问题。首先就是实例级别的统计信息,它包含了操作系统层面、server层和InnoDB等共计55个指标。而后把它放到一个Performance表中,每秒钟进行一次统计。通过这些统计的信息能够剖析零碎呈现问题的起因。
3. 实用性:Performance Insight可诊断、可度量
这个是对象级别性能度量的指标,包含表和索引。这些统计能够反对业务数据模型的优化和变更。
还有语句级别的统计信息。MySQL自身具备语句级别统计信息,然而它的统计信息不够丰盛,因而在这个根底上咱们又减少了更多实用性的统计信息,比方CPU的应用工夫,加锁耗费的工夫等。
MySQL里用了大量的Mutex来保障多线程之间的数据拜访,咱们加了对于Mutex加锁时耗费工夫的统计,不便对数据库热点的剖析。
这些统计信息提供了更充沛的数据根据,帮忙咱们做疾速的问题定位。
4. 稳定性:Buffer Pool优化
在稳定性方面,咱们也做了大量的工作。首先是Buffer Pool的优化。
云上用户会有长期变配的需要。举个例子,在业务顶峰时,若心愿实例长期规格变大,过了顶峰之后再把规格降下来。MySQL是反对线上的resize,然而它的稳定性不够好。在做Online resize对性能的影响还是比拟大的。AliSQL针对这个做了优化后,能够看到下图蓝色线条是动静变配的稳定曲线,稳定性好很多。
5. 稳定性:Concurrency Control 并发管制
用户经常会碰到几个SQL过去一下子就把实例的CPU打满的状况,或者是内存耗光等相似的状况。Concurrency Control并发管制这个性能,能够让用户依据理论应用状况,对SQL限度执行个数,以进步实例整体运行的稳定性。
6. 安全性:TDE反对国密SM4
企业级用户对于安全性的要求越来越高,对于各种各样的加密、明码强度、生命周期等要求也越来越多。AliSQL在平安这块做了更全面的反对,比方对于加密来讲,除了反对TDE这种AES的加密算法,还反对国密加密算法SM4,对于有涉密要求的用户能够用SM4的加密算法来保证数据的安全性。
7. 安全性:Recycle Bin避免误删除
当用户在做删除表或是Truncate表的时候,应用这个回收站性能,并不会把数据文件间接删除掉,而是会把这些表放到一个回收站里,这样就防止了用户在误删之后数据失落的危险,误删除后还能通过回收站把删除的数据疾速找回。
8. 安全性:Flashback Query
不仅是表级的误删除,当咱们对某一些数据更新的范畴谬误了之后,应用Flashback机制,能够复原到更新前的历史版本。同时,用户还能够自定义查问某个工夫戳的某个数据。
所以Flashback Query对误操作删除复原或是回档需要是很无效的办法。
9. 高性能:Binlog In Redo
比照原生MySQL,AliSQL的性能晋升很多。首先介绍的是Binlog In Redo性能。家喻户晓,在MySQL外面,事务提交的时候须要长久化两次,因为要执行两阶段的事务提交过程。这外面做了一个改良,即能够把Binlog写到Redo外面,这样的话就只须要长久化一次Redolog,Binlog能够异步刷盘。
通过这种形式,用户事务在提交的时候就只须要一次刷盘动作,因而时延会升高,吞吐量会增大。
上图是基于两个Binlog in Redo版本的测试后果。通过左侧第二个版本的数据,咱们发现性能会进步很多。对于Update non index来讲,能够有大略38%的性能晋升。对于write only来讲,也能够达到25%的性能晋升。
10. 高性能:Fast Query Cache
AliSQL针对Query Cache在并发管制、内存治理和缓存机制等等做了大量的优化。
优化之后,它的性能晋升非常明显。在point select的场景下,性能晋升甚至能够达到100%以上。通过测试发现,在rewrite模式命中率比拟低的状况下,简直没有任何性能损失。所以用户在读比拟多的场景就能够把Query Cache关上,能够保持稳定高效的状态。
11. 高性能:DDL Optimization
围绕DDL咱们做了大量优化。
用户在应用DDL的时候会发现,如果表特地大须要做rebuild或更新数据等操作的时候,效率非常低。次要是因为DDL利用Buffer Pool的模型是效率低下的模型。优化之后,对于rebuild表的这种操作效率会高很多,对于其余SQL语句的影响也会升高很多。
下图是针对Create Index和Optimize Table的测试,能够看到优化之后,操作都会有10倍以上的性能晋升。
三、XA Crash Safe 介绍
1. XA Crash Safe背景
抛开XA Crash Safe自身,MySQL自身也有Crash Safe机制。为什么会须要这样的机制呢,因为在MySQL里,同时包含Binlog和数据两个局部,能够了解为存了两份截然不同的数据。为了保障这两份数据的一致性,MySQL Crash Safe实现了两阶段提交机制。为了保障Binlog和数据的一致性,任何用户的事务都会被转化成为两阶段的事务,首先就是进行prepare,而后再写Binlog并长久化,最初做事务的提交。所以在这两个阶段的提交过程中,Prepare、刷Redo、写Binlog和刷Binlog的执行程序是放弃不变的。
如何保障Crash Safe呢?这要看它复原的处理过程。在理论的事务执行过程中,只有是Binlog有这个事务,肯定是Prepare的状态。那么利用这个准则,在MySQL Crash重启的时候,它会取出所有曾经prepare的事务,把它们的XID取出来,扫描最初一个Binlog文件,而后确认XID所对应的事务是否曾经存储到Binlog里了。如果曾经存储过了,就间接提交即可;如果还没有存储,就回滚掉。通过这个Crash Recovery机制后,Binlog里的数据就和引擎外面的数据保持一致了。
对于普通用户事务能够用两阶段来保障Crash Safe,那么对于用户的XA事务怎么解决呢?
在Binlog里会把这个事务分为独立的两局部,当用户执行XA Prepare的时候,会写Binlog文件,而后把这个Prepare状态执行到引擎里,这是齐全独立的。用户在XA Commit里,能够在任何工夫执行,当用户在执行XA Commit之后会被再记录一次Binlog,所以这两者是齐全脱离的。
对于一般的用户事务,执行过程只记录一次Binlog,而且整个事务是一个根本的单元存在Binlog中的;对于XA事务,这就是离开的。而且它整个过程是先写Binlog,而后才去把状态长久化到引擎中,做引擎的prepare。对于MySQL来讲,不能保障内部XA事务数据和Binlog的一致性。
也就是说当写完Binlog,还没有在引擎中执行prepare和commit,这个时候就Crash了,那么它起来之后就变成,Binlog里有事务记录,而在引擎里却失落了,兴许只以prepare的状态停留在那里,这就没有被提交。
2. XA Crash Safe:基于MySQL 5.7的修复
1)调整执行程序
为了更好的反对分布式数据库系统,在MySQL 5.7的时候,阿里就做过对于XA Crash Safe的修复。这个修复是把执行程序做了颠倒,即先执行引擎的Prepare,再写Binlog,这样它就跟一般事务的过程一样了。在Prepare之后做Crash,如果用户的XA事务做了Prepare之后没有记Binlog,那么数据就会被回滚掉。然而因为XA事务跟一般事务不太一样,须要更多解决来反对回滚,而且它也不是一个欠缺的计划。因为用户具备多样性,比方用户执行了一个事务然而并没有记Binlog,这个时候就没法辨别是否记录了Binlog。另外,XA事务的Prepare和Commit是离开的,当用户将Prepare事务记录到很久以前的Binlog里了,也不能辨别用户是否记录了Binlog。
这种状况下就须要一个解决方案,即在做Binlog rotation时候,要把所有Prepare事务的XID记录到Binlog中。这样咱们就能够通过最初一个Binlog去理解所有Prepare状态的XID,而后就能够通过Rollback的形式放弃Binlog和数据的一致性。
2)调整Recovery逻辑
Commit执行了另外一种逻辑,即先执行Binlog,在执行后发现事务是Prepare状态,且在Binlog中记录了Commit或Rollback,那么执行Commit或Rollback。
这就是MySQL 5.7上XA Crash Safe的修复的过程。
3. XA Crash Safe:MySQL 8.0 Gtid和事务的一致性
MySQL 8.0采纳了另外一种办法。介绍这个办法之前,首先介绍下MySQL 8.0 Gtid和事务的一致性。在MySQL8.0.17的时候,引入克隆性能,这个性能能够把Gtid记到事务的undo里。记到Undo里的过程也很简略,在Prepare的时候还是先记Binlog,而后引擎里做事务Prepare的时候,去监测这个事务是否有Gtid。如果有,在批改事务状态时会连通Gtid一起写到Undo里。如果Crash之后,Prepare丢了,那么Gtid肯定也是不存在的,反之亦然。在Commit的时候也同理。这样做,克隆的时候用户应用起来就会非常简单。
然而Rollback是个特例,尤其是对于XA事务来说。Rollback也会记录一个Gtid。Rollback在引擎里的做法是,把事务状态改成active之后就会天然回滚,所以在active的时候它也会记一个Gtid,所以XA Rollback会记录Binlog也会产生Gtid。整个操作也是原子的。
Gtid最终会长久化到Gtid_executed表里。之所以要做汇总是因为Undo自身须要Purge,否则会越来越大,而且检索效率也非常低。所以尽管在Prepare后会放进Undo里,然而实际上最初都会汇总到Gti_executed表中,而后会有一个独自的Gtid Flush的线程,它会周期性的把Gtid list里的Gtid写到Gtid_executd表中。写到表后,只须要继续化整个表后,undo就能够丢掉了,这样始终会有一个残缺的Gtid汇合。
对于内部XA事务会记录两个Gtid,一个是Prepare的时候,一个是Commit的时候。最后实现这个性能的时候,只会记录一个Gtid,也就是说在commit的时候会把prepare的给笼罩了。这就要求,在Commit之前须要把Prepare的Gtid长久化到Gtid executed表里,效率非常低。起初官网优化成将两个Gtid别离存在两个地位,这就大大提高了效率。
通过以上的优化之后,咱们能够看到Gtid和事务数据之间的关系,是Gtid Executed表中的Gtid代表了InnoDB中曾经执行了的事务的Gtid。这两者之间是原子对应的关系。
通过这样的对应关系,咱们能够在系统启动的时候做Apply Binlog这样的操作,来保障内部XA事务的Crash Safe。
依据Gtid Executed表中的Gtid就能够晓得哪些事务在引擎里存在,而后通重放Binlog里的事务将引擎里的数据补齐。通过这样的形式,不须要批改过增加Binlog Event,原来的recover过程也不须要变动。只须要在recover之后,查看Gtid Executed的表,而后比照Binlog。将短少的事务从新Apply一下就能够了,这样就能够保障XA事务的Crash Safe。
原文链接
本文为阿里云原创内容,未经容许不得转载。