简介: 近几年,随着分布式数据库系统的兴起,特别是基于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。

原文链接

本文为阿里云原创内容,未经允许不得转载。

阿里云RDS深度定制-XA Crash Safe的更多相关文章

  1. 阿里云RDS数据库改造迁移方案

    1. 改造原因 (1) 由于历史原因, 本应该是同一个库的表分布在两个数据库中,需要对这两个库进行合并. (2) 已有的数据库性能无法满足业务的增长需要, 查询卡,慢问题突出. (3) 当前自建Mys ...

  2. 强强联合 阿里云 RDS for SQL Server 与 金蝶 K/3 WISE 产品实现兼容适配

    强强联合 阿里云 RDS for SQL Server 与 金蝶 K/3 WISE 产品实现兼容适配,原K/3 WISE用户通过简单配置就可以无缝搭配RDS SQL Server使用,不需再费时费力自 ...

  3. 抱歉!15:44-16:39阿里云RDS故障造成全站不能正常访问

    非常非常抱歉!2016年3月7日15:44-16:39,由于阿里云RDS(云数据库)故障,造成全站不能正常访问,给您带来了很大很大的麻烦,恳请您的谅解! 故障是在15:44开始出现的,应用日志中出现大 ...

  4. 云计算之路-阿里云上:数据库连接数过万的真相,从阿里云RDS到微软.NET Core

    在昨天的博文中,我们坚持认为数据库连接数过万是阿里云RDS的问题,但后来阿里云提供了当时的数据库连接情况,让我们动摇了自己的想法. 帐户 连接数 A 4077 B 3995 C 741 D 698 E ...

  5. 阿里云RDS for SQL Server使用的一些最佳实践

    了解RDS的概念 这也是第一条,也是最重要的一条,在使用某项产品和服务之前,首先要了解该产品或服务的功能与限制,就像你买一个冰箱或洗衣机,通常也只有在阅读完说明书之后才能利用起来它们的所以功能,以及使 ...

  6. 阿里云RDS for SQL Server测试吐槽

    最近测试了一下阿里云RDS for SQL Server,有些设计简直就是反人类,让人不得不吐槽一番. 1:控制台创建数据库时,数据库名不能包含大小字母. 如上截图所示,数据库名称不能包含大写字母,好 ...

  7. 阿里云 RDS for MySQL支持什么引擎

    问题:我们的服务器是买的是阿里云,mysql版本5.011 ,本地和服务器配置一样,在本地可以安装discuzX3.4,但是在服务器上却报错了,如下图: 找了半天,才知道阿里云RDS 支持的mysql ...

  8. 阿里云rds 备份和还原

    阿里云rds 备份和还原 转发:https://www.cnblogs.com/lin1/p/8617764.html 转发:https://help.aliyun.com/knowledge_det ...

  9. 阿里云RDS的mysql数据库占用空间超过90%的处理

    阿里云RDS数据库最大支持2T,目前已经占用了90%,如果进行分库或者迁移比较麻烦,思路是找出占用空间过大的日志或不重要的文件进行删除操作 查询所有数据库占用磁盘空间大小的SQL语句: show bi ...

  10. 【故障公告】阿里云 RDS 数据库服务器 CPU 100% 造成全站故障

    非常非常抱歉,今晚 19:34 ~ 21:16 园子所使用的阿里云 RDS 数据库服务器突然出现 CPU 100% 问题,造成全站无法正常访问,由此您带来了很大的麻烦,请您谅解. 故障经过是这样的.1 ...

随机推荐

  1. Linux 运维工程师面试真题-5-常考题目汇总

    Linux 运维工程师面试真题-5-常考题目汇总 1.解释下什么是 GPL,GNU,自由软件? GPL:(通用公共许可证):一种授权,任何人有权取得.修改.重新发布自由软件的权力. GNU:(革奴计划 ...

  2. 游戏引擎中的实时渲染和在V-Ray中渲染有什么区别 2022-11-25

    游戏引擎中的实时渲染和在V-Ray中渲染有什么区别,下面我们一起来分析一下,从2个方面来具体分析实时渲染和在V-Ray中渲染种的不一样的区别. 原理区别 VRay等渲染器原理上叫做离线渲染(Offli ...

  3. 【Leetcode】63. 不同路径 II

    题目(链接) 一个机器人位于一个m x n网格的左上角 (起始点在下图中标记为 "Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为 ...

  4. Spring Boot框架中使用Jackson的处理总结

    1.前言 通常我们在使用Spring Boot框架时,如果没有特别指定接口的序列化类型,则会使用Spring Boot框架默认集成的Jackson框架进行处理,通过Jackson框架将服务端响应的数据 ...

  5. 如何使用 JavaScript 导入和导出 Excel

    前言 在现代的Web应用开发中,与Excel文件的导入和导出成为了一项常见而重要的任务.无论是数据交换.报告生成还是数据分析,与Excel文件的交互都扮演着至关重要的角色.本文小编将为大家介绍如何在熟 ...

  6. LOTO示波器电源环路增益分析客户实测

    我们在之前有文章介绍过LOTO示波器+信号源扫频测电源环路增益稳定性的方法和过程,可以参考演示视频如下: https://www.ixigua.com/7135738415382790663?logT ...

  7. module 'numpy' has no attribute 'bool'

    module 'numpy' has no attribute 'bool' 问题: Traceback (most recent call last): File "/home/test. ...

  8. Java面试题【3】

    20)什么是线程安全? 含义:当多个线程访问某个方法时,不管你通过怎样的调用方式或者说这些线程如何交替的执行,我们在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以 ...

  9. SpringMVC转发和重定向的区别是什么

    转发和重定向 视图解析器 <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalRe ...

  10. 如何拿到接口返回的消耗token

    SemanticKernel 以下引用自官方案例 Text模型 使用Kernel FunctionResult functionResult = await kernel.InvokePromptAs ...