关于主从复制:MySQL主从复制延迟解决方案

3次阅读

共计 5704 个字符,预计需要花费 15 分钟才能阅读完成。

后面一篇,咱们学习到了 MySQL 多版本并发管制(MVCC)实现原理,这一篇咱们接着学习 MySQL 主从复制模式下的提早解决方案。

MySQL 主从提早是指从库的数据同步比主库略有提早,造成数据差别。MySQL 主从复制模式个别采纳以下办法升高提早:

1、优化网络环境:主从复制时,减小主从服务器之间网络提早对数据库同步的影响。能够思考优化网络之间连贯的带宽、减少从库的硬件性能等。

2、减少从库数量:减少从库数量能够减少数据同步的速度和可靠性,同时也能缩小每个从库的累赘,进步从库响应速度。

3、调整数据库相干参数:能够调整一些 MySQL 数据库中的相干参数,比方调整 binlog 格局、binlog 缓冲区大小、innodb_flush_log_at_trx_commit 等参数,采纳半同步模式,以放慢数据的同步速度。

4、分区数据库:将数据库分成多个区,每个从库只复制本人所须要的数据区,能够无效的缩小排队梗塞、网络传输等方面的提早问题。

综上所述,优化网络环境、减少从库数量、调整数据库相干参数、分区数据库等办法能够无效的升高 MySQL 主从复制模式的提早。

什么是主从提早

在探讨如何解决主从提早之前,咱们先理解下什么是主从提早。

为了实现主从复制,从库须要通过 I/O 线程获取主库中 dump 线程读取的 binlog 内容并写入到本人的中继日志 relay log 中,从库的 SQL 线程再读取中继日志,重做中继日志中的日志,相当于再执行一遍 SQL,更新本人的数据库,以达到数据的一致性。

与数据同步无关的工夫点次要包含以下三个:

1、主库执行完一个事务,写入 binlog,将这个时刻记为 T1;

2、之后传给从库,将从库接管完这个 binlog 的时刻记为 T2;

3、从库执行实现这个事务,将这个时刻记为 T3。

所谓主从提早,就是同一个事务,从库执行实现的工夫与主库执行实现的工夫之差,也就是 T3 – T1。

能够在备库上执行 show slave status 命令,它的返回后果外面会显示 seconds_behind_master,用于示意以后备库提早了多少秒。
seconds_behind_master 的计算方法是这样的:

1、每个事务的 binlog 外面都有一个工夫字段,用于记录主库上写入的工夫;

2、备库取出以后正在执行的事务的工夫字段的值,计算它与以后零碎工夫的差值,失去 seconds_behind_master。

在网络失常的时候,日志从主库传给从库所需的工夫是很短的,即 T2 – T1 的值是十分小的。也就是说,网络失常状况下,主从提早的次要起源是从库接管完 binlog 和执行完这个事务之间的时间差。

因为主从提早的存在,咱们可能会发现,数据刚写入主库,后果却查不到,因为可能还未同步到从库。主从提早越重大,该问题也更加显著。

主从提早的起源

主库和从库在执行同一个事务的时候呈现时间差的问题,次要起因包含但不限于以下几种状况:

1、有些部署条件下,从库所在机器的性能要比主库性能差。

2、从库的压力较大,即从库接受了大量的申请。

3、执行大事务。因为主库上必须等事务执行实现才会写入 binlog,再传给备库。如果一个主库上语句执行 10 分钟,那么这个事务可能会导致从库提早 10 分钟。

4、从库的并行复制能力。

主从提早的解决方案

解决主从提早次要有以下计划:

1、配合 semi-sync 半同步复制;

2、一主多从,摊派从库压力;

3、强制走主库计划(强一致性);

4、sleep 计划:主库更新后,读从库之前先 sleep 一下;

5、判断主备无提早计划(例如判断 seconds_behind_master 参数是否曾经等于 0、比照位点);

6、并行复制 — 解决从库复制提早的问题;

这里次要介绍我在我的项目中应用的几种计划,别离是半同步复制、实时性操作强制走主库、并行复制。

半同步复制

MySQL 有三种同步模式,别离是:

「异步复制」:MySQL 默认的复制即是异步的,主库在执行完客户端提交的事务后会立刻将后果返给客户端,并不关怀从库是否曾经接管并解决。这样就会有一个问题,一旦主库宕机,此时主库上曾经提交的事务可能因为网络起因并没有传到从库上,如果此时执行故障转移,强行将从晋升为主,可能导致新主上的数据不残缺。

「全同步复制」:指当主库执行完一个事务,并且所有的从库都执行了该事务,主库才提交事务并返回后果给客户端。因为须要期待所有从库执行完该事务能力返回,所以全同步复制的性能必然会收到重大的影响。

「半同步复制」:是介于全同步复制与全异步复制之间的一种,主库只须要期待至多一个从库接管到并写到 Relay Log 文件即可,主库不须要期待所有从库给主库返回 ACK。主库收到这个 ACK 当前,能力给客户端返回“事务实现”的确认。

MySQL 默认的复制是异步的,所以主库和从库的数据会有肯定的提早,更重要的是异步复制可能会引起数据的失落。然而全同步复制又会使得实现一个事务的工夫被拉长,带来性能的升高。因而我把眼光转向半同步复制。从 MySQL 5.5 开始,MySQL 以插件的模式反对 semi-sync 半同步复制。

绝对于异步复制,半同步复制进步了数据的安全性,缩小了主从提早,当然它也还是有肯定水平的提早,这个提早起码是一个 TCP/IP 往返的工夫。所以,半同步复制最好在低延时的网络中应用。

须要留神的是:

1、主库和从库都要启用半同步复制才会进行半同步复制性能,否则主库会还原为默认的异步复制。

2、如果在期待过程中,等待时间曾经超过了配置的超时工夫,没有收到任何一个从库的 ACK,那么此时主库会主动转换为异步复制。当至多一个半同步从节点赶上来时,主库便会主动转换为半同步复制。

半同步复制的潜在问题

在传统的半同步复制中(MySQL 5.5 引入),主库写数据到 binlog,并且执行 commit 提交事务后,会始终期待一个从库的 ACK,即从库写入 Relay Log 后,并将数据落盘,再返回给主库 ACK,主库收到这个 ACK 当前,能力给客户端返回“事务实现”的确认。

这样会呈现一个问题,就是实际上主库曾经将该事务 commit 到了存储引擎层,利用曾经能够看到数据产生了变动,只是在期待返回而已。如果此时主库宕机,可能从库还没写入 Relay Log,就会产生主从库数据不统一。

为了解决上述问题,MySQL 5.7 引入了加强半同步复制。针对下面这个图,“Waiting Slave dump”被调整到了“Storage Commit”之前,即主库写数据到 binlog 后,就开始期待从库的应答 ACK,直到至多一个从库写入 Relay Log 后,并将数据落盘,而后返回给主库 ACK,告诉主库能够执行 commit 操作,而后主库再将事务提交到事务引擎层,利用此时才能够看到数据产生了变动。

当然之前的半同步计划同样反对,MySQL 5.7.2 引入了一个新的参数 rpl_semi_sync_master_wait_point 进行管制。这个参数有两种取值:

1、AFTER_SYNC:这个是新的半同步计划,Waiting Slave dump 在 Storage Commit 之前。

2、AFTER_COMMIT:这个是老的半同步计划。

在 MySQL 5.5 – 5.6 应用 after_commit 的模式下,客户端事务在存储引擎层提交后,在主库期待从库确认的过程中,主库宕机了。此时,后果尽管没有返回给以后客户端,但事务曾经提交了,其余客户端会读取到该已提交的事务。如果从库没有接管到该事务或者未写入 relay log,同时主库宕机了,之后切换到备库,那么之前读到的事务就不见了,呈现了幻读,也就是数据失落了。

MySQL 5.7 默认值则是 after_sync,主库将每个事务写入 binlog,传给从库并刷新到磁盘 (relay log)。主库等到从库返回 ack 之后,再提交事务并且返回 commit OK 后果给客户端。即便主库 crash,所有在主库上曾经提交的事务都能保障曾经同步到从库的 relay log 中,解决了 after_commit 模式带来的幻读和数据失落问题,故障切换时数据一致性将失去晋升。因为从库没有写入胜利的话主库也不会提交事务。并且在 commit 之前期待从库 ACK,还能够沉积事务,有利于 group commit 组提交,有利于晋升性能。

但这样也会有个问题,假如主库在存储引擎提交之前挂了,那么很显著这个事务是不胜利的,但因为对应的 Binlog 曾经做了 Sync 操作,从库曾经收到了这些 Binlog,并且执行胜利,相当于在从库上多了数据(从库上有该数据而主库没有),也算是有问题的,但多了数据个别不算重大的问题。它能保障的是不丢数据,多了数据总比丢数据要好。

一主多从

如果从库承当了大量查问申请,那么从库上的查问操作将消耗大量的 CPU 资源,从而影响了同步速度,造成主从提早。那么咱们能够多接几个从库,让这些从库来独特分担读的压力。

简而言之,就是加机器,办法简略粗犷,但也会带来肯定老本。

强制走主库计划

如果某些操作对数据的实时性要求比拟刻薄,须要反映实时最新的数据,比如说波及金钱的金融类零碎、在线实时零碎、又或者是写入之后马上又读的业务,这时咱们就得放弃读写拆散,让此类的读申请也走主库,这就不存提早问题了。

当然这也失去了读写拆散带给咱们的性能晋升,须要适当取舍。

并行复制

个别 MySQL 主从复制有三个线程参加,都是单线程:Binlog Dump 线程、IO 线程、SQL 线程。复制呈现提早个别出在两个中央:

1、SQL 线程忙不过来(次要起因);

2、网络抖动导致 IO 线程复制提早(主要起因)。

日志在备库上的执行,就是备库上 SQL 线程执行中继日志(relay log)更新数据的逻辑。

在 MySQL 5.6 版本之前,MySQL 只反对单线程复制,由此在主库并发高、TPS 高时就会呈现重大的主备提早问题。从 MySQL 5.6 开始有了多个 SQL 线程的概念,能够并发还原数据,即并行复制技术 。这能够很好的解决 MySQL 主从提早问题。

从单线程复制到最新版本的多线程复制,两头的演变经验了好几个版本。其实说到底,所有的多线程复制机制,都是要把只有一个线程的 sql_thread,拆成多个线程,也就是都合乎上面的这个多线程模型:

coordinator 就是原来的 sql_thread,不过当初它不再间接更新数据了,只负责读取直达日志和散发事务。真正更新日志的,变成了 worker 线程 。而 worker 线程的个数,就是由参数 slave_parallel_workers 决定的。

因为 worker 线程是并发运行的,为了保障事务的隔离性以及不会呈现更新笼罩问题,coordinator 在散发的时候,须要满足以下这两个根本要求:

更新同一行的两个事务,必须被散发到同一个 worker 中(防止更新笼罩)。

同一个事务不能被拆开,必须放到同一个 worker 中(保障事务隔离性)。

各个版本的多线程复制,都遵循了这两条根本准则。

以下是按表散发策略和按行散发策略,能够帮忙了解 MySQL 官网版本并行复制策略的迭代:

1、按表散发策略 :如果两个事务更新不同的表,它们就能够并行。因为数据是存储在表里的,所以按表散发,能够保障两个 worker 不会更新同一行。

按表散发的计划,在多个表负载平均的场景里利用成果很好,但毛病是:如果碰到热点表,比方所有的更新事务都会波及到某一个表的时候,所有事务都会被调配到同一个 worker 中,就变成单线程复制了。

2、按行散发策略 :如果两个事务没有更新雷同的行,则它们在备库上能够并行。显然,这个模式要求 binlog 格局必须是 row。

按行并行复制的计划解决了热点表的问题,并行度更高,但毛病是:相比于按表并行散发策略,按行并行策略在决定线程散发的时候,须要耗费更多的计算资源。

MySQL 5.6 版本的并行复制策略
MySQL 5.6 版本,反对了并行复制,只是反对的粒度是按库并行(基于 Schema)。

其核心思想是:不同 schema 下的表并发提交时的数据不会相互影响,即从库能够对 relay log 中不同的 schema 各调配一个相似 SQL 线程性能的线程,来重放 relay log 中主库曾经提交的事务,保持数据与主库统一。

如果在主库上有多个 DB,应用这个策略对于从库复制的速度能够有比拟大的晋升。但通常状况下都是单库多表,那基于库的并发也就没有什么作用,根本无法并行重放,所以这个策略用得并不多。

MySQL 5.7 的并行复制策略

MySQL 5.7 引入了基于组提交的并行复制,参数 slave_parallel_workers 设置并行线程数,由参数 slave-parallel-type 来管制并行复制策略:

配置为 DATABASE,示意应用 MySQL 5.6 版本的按库并行策略;

配置为 LOGICAL_CLOCK,示意应用基于组提交的并行复制策略;

利用 binlog 的组提交 (group commit) 机制,能够得出一个组提交的事务都是能够并行执行的,起因是:可能在同一组里提交的事务,肯定不会批改同一行(因为 MySQL 的锁机制),因为事务曾经通过锁抵触的测验了

基于组提交的并行复制具体流程如下

1、在一组外面一起提交的事务,有一个雷同的 commit_id,下一组就是 commit_id+1;commit_id 间接写到 binlog 外面;

2、传到备库利用的时候,雷同 commit_id 的事务散发到多个 worker 执行;

3、这一组全副执行实现后,coordinator 再去取下一批执行。

所有处于 prepare 和 commit 状态的事务都是能够在备库上并行执行的。

binlog 的组提交的两个无关参数:

binlog_group_commit_sync_delay 参数,示意提早多少微秒后才调用 fsync 刷盘;

binlog_group_commit_sync_no_delay_count 参数,示意累积多少次当前才调用 fsync。

这两个参数是用于成心拉长 binlog 从 write 到 fsync 的工夫,以此缩小 binlog 的写盘次数。在 MySQL 5.7 的并行复制策略里,它们能够用来制作更多的“同时处于 prepare 阶段的事务”。能够思考调整这两个参数值,来达到晋升备库复制并发度的目标。

正文完
 0