MySQL 8.0复制性能的提升
MySQL复制从问世到现在已经经历了多个年头,它的稳定性和可靠性也在稳步的提高。这是一个不停进化的过程,由于MySQL的很多重要功能都是依赖于复制,所以复制的快速发展也是很容易理解的。
在MySQL的上一个版本当中,MySQL通过实现真正意义的并行复制将复制的性能提升到了一个新的层面,因为在MySQL 5.6的版本中,虽然号称是实现了并行复制,但是并行复制是schema级别的,即如果binlog row event操作的是不同的schema的对象,在确定没有DDL和foreign key依赖的情况下,就可以实现并行复制,并不能称为真正意义的复制。它只是将不同schema的事物分开来执行,并不能真正意义的实现并行复制(比如主从架构只有一个schema的情况还是很多见的)。当然如果你的主从架构有多个schema的话,5.6的并行复制是对性能有很大的提升的。
MySQL5.7的并行复制是基于组提交(group commit)的并行复制的方法,5.7的并行复制,即使你的多个事物是对同一个schema进行操作,也能够在从库上并行回放。简而言之,就是多个事物如果相互不影响,在刷盘的时候是能够作为一个组来提交刷盘,我们甚至可以通过在从库手动设置binlog_group_commit_sync_delay这个参数控制日志在刷盘前日志提交要等待的时间,从而提高从库复制的效率。
这个方案看起来似乎很完美,但是并不是没有缺点。事物提交的延迟,最终都会影响到应用端的用户体验。当然,你可以将延迟设置在几毫秒内,但是即使是这样还是会影响到客户端的时效性。
MySQL8.0复制性能的提升
截至目前(2017年8月)的MySQL 8.0最新发布了beta版本,起初是为了组复制(GR)开发的,但是由于GR在底层也是使用的普通复制,普通复制也受益匪浅。我们提到的改进是8.0在binary log中加入了一些依赖的跟踪信息。在MySQL8.0中,MySQL通过一种方法能够存储记录那些行受到了那些事物的影响信息(称之为writeset),而且MySQL可以对比不同事物的writeset信息,这样就可以将两个事物是否是对同一个对象的同一行进行操作,如果不是,就可以并行执行。这相比于MySQL5.7的复制又提升了一个级别。你需要牢记的事,最终,从库看到的数据可能会出现和主库不同的情况,这种情况是永远不会发生在主库的。发生这种情况的原因是因为,从库执行事物的顺序可能和主库执行事物的顺序是不一致引起的。虽然这并不能称之为一个问题,MySQL5.7的并行复制机制也是会产生这个问题的,除非你指定启用了slave-preserve-commit-order这个参数。
为了避免这种情况的发生,MySQL8.0新增了binlog_transaction_dependency_tracking 参数来解决这个问题。他可以取以下三个值:
COMMIT_ORDER:默认设置,默认设置为MySQL5.7的默认机制
WRITESET:它能够实现更好的并行化,并且主库开始在二进制日志中存储写入writeset信息
WRITESET_SESSION:设置事物在从库是顺序执行的,这就消除了我们上面说的从库查看数据可能会存在和主库不同的情况。设置为这个值会虽然会降低并行复制的性能,但是相比默认设置来说,性能还是有很大提升的。
基准测试
7月份,Vitor Oliveira在mysqlhighavailability.com上写了一篇文章,他试图测试复制新模式下的性能。在他的测试中,使用了最理想的情况-没有做数据持久化,借此来对比新旧复制模式下的性能。我们决定使用相同的方法,这一次在一个更接近生产的设置:使用log_slave_updates启用二进制日志。持久化参数在MySQL8.0中是默认的(sync_binlog=1-这在MySQL8.0是默认的,开启了双写缓存和innodb校验),innodb_flush_log_at_trx_commit设置为2。
我们看一下机器的配置,32G,8核(slave_parallel_workers 设置为8),测试工具为sysbench的oltp_read_write.lua脚本,32个表中的1600万行存储在1000GB gp2卷上(即3000 IOPS),我们在所有复制模式下分别开1,2,4,8,16,32并发对性能进行测试和对比。测试过程如下:停止slave,执行100000个事物,打开slave并计算从库追上主库的时间。
首先,我们不知道当使用1个线程执行sysbench时发生了什么。每次测试在暖机运行后执行了五次。这个特殊的配置被测试了两次 - 结果是稳定的:单线程工作量是最快的。我们将进一步研究,以了解到底是为什么。
除此之外,一切都符合我们的预期。COMMIT_ORDER是最慢的,特别是对于低流量,2-8线程。 WRITESET_SESSION通常比COMMIT_ORDER效率更好,但是对于低并发流量,它比WRITESET慢。
这对我来说有什么好处?
第一个益处是显而易见的,如果你的数据库负载较高,而且从库有延迟的话,你可以通过将主库升级为MySQL 8.0来提升复制的性能。这里需要留意两个方面:第一,此功能向下兼容,即使的从库是MySQL 5.7,性能也能有很好的提升;第二,MySQL8.0暂时并没有GA,所以说不推荐在生产库使用Beat版本。MySQL8.0对复制的提升不仅能够很好解决从库延迟的问题,这种情况下主从的延迟几乎是没有的,除非你重新添加一个新的slave或者重新配置了slave的时候可能会产生延迟。如果使用“WRITESET”模式将使得配置新主机的过程更加快捷。
总而言之,这个功能可能比你预期的产生更大的影响,鉴于所有基准测试,显示MySQL处理低并发性流量时的性能回归,任何有助于提高在这种环境中复制的效率的任何操作都将是巨大的进步。
如果你使用了级联复制,这也是你需要了解的一个功能。任何中间主节点都会将事务处理和执行的方式添加一些序列化的信息-但是真是情况却是,中间节点的负载要比主库要小。因为他使用了一些写入组件来实现更好的并行化,从而提高了自身和自身从库的并行效率。甚至你可以通过将中间节点的主库升级为MySQL8.0来提高下层从库的节点(请记住,MySQL 5.7从站可以识别riteet数据并使用它,即使它不能自己生成它)。当然,MySQL 8.0到5.7的主从复制听起来确实是很棘手的,这倒不是因为MySQL8.0还没有GA的原因。当然在一些情况下,这可以使从库的CPU使用率得到很好的提升。
MySQL复制的其他变化
MySQL8.0对于复制最主要的提升就是引入了writesets,但是这并不是唯一的变化。让我们来看一下其他的一些重要的改进,如果你的主库是MySQL5.0以下版本,8.0将不再支持读取它的二进制日志,所以如果你使用的还是老版本的MySQL进行传统复制,是时候升级你的数据库版本了。 为了确保复制的安全性和稳定性,修改了复制了默认参数:master_info_repository 和relay_log_info_repository 默认将设置为table,Expire_log_days 默认设置为30,除了Expire_log_days ,还新增了一个参数binlog_expire_log_seconds,这将对binlog的轮询策略实现更细粒度的管控。在binlog信息中将会添加一些额外的时间戳信息,目的是能够更好的观察监控复制的延迟,达到微妙级别。
总而言之,这不是与MySQL复制相关的更改和功能的完整列表。你可以访问这里获得完整的列表信息,了解复制功能的所有的改进和提升。
如我们所知,MySQL的复制正在变化,而且越来越好。正如我们开始所说,虽然这是一个缓慢进步的过程,但是我们已经可以看到了它的大好前景了。而且我们也很高兴看到Group Replication的底层复制也是采用了常规复制的功能来。