0、导读
目前很多公司中的生产环境中都使用了MySQL Replication ,也叫 MySQL 复制,搭建配置方便等很多特性让 MySQL Replication 的应用很广泛,我们曾经使用过一主拖20多个从库来分担业务压力。关于 MySQL Replication 的文章网络上也有很多,但大多数都是讲如何搭建MySQL Replication,并没有说清楚如何才能搭建出高可靠的MySQL Replication。这篇文章也对半同步复制,无损复制,多源复制做了讲解。 复制有哪些用途
复制是如何工作的从上图中可以看到,复制的主要步骤:
binlog二进制日志文件,用于记录 MySQL 的数据变更。 relay-log中继日志文件,slave 的I/O线程读取 master 的 binlog,记录到 relay-log 中,然后 SQL 线程会读取 relay-log 日志的内容并应用到 slave 服务器。 binlog 记录的格式STATEMENT(记录操作的SQL语句)
ROW(记录操作的每一行数据的变化信息,RC 隔离级别,必须是 row 格式)
MIXED(混合模式)
binlog Events我们都知道 binlog 日志用于记录所有对 MySQL 的操作的变更,而这每一个变更都会对应的事件,也就是 Event,index文件记录了所有的 binlog 位置,每个 binlog 会有 header event,rotate 三个 event,binlog 的结构如下。 常见的Event如下:
在了解了以上基础的内容后,我们可以带着以下的三个问题去学习复制到底是怎样工作的。
务是如何提交的?事务提交先写 binlog 还是 redo log?以上的图片中可以看到,事务的提交主要分三个主要步骤:
为什么 MySQL 有 binlog,还有 redo log?这个是因为 MySQL 体系结构的原因,MySQL 是多存储引擎的,不管使用那种存储引擎,都会有 binlog,而不一定有 redo log,简单的说,binlog 是 MySQL Server 层的,redo log 是 InnoDB 层的。 如何保证这两部分的日志做到一致性?事务提交的过程上面已经说到,需要写 redo log 还要写 binlog,那么如何保证数据的一致性呢,如果不能保证写这两个文件在同一事务中,那么就会造成数据不一致,这个不一致包括MySQL crash时和主从复制的数据不一致。 面试时经常会问的一个问题,影响MySQL写入性能、数据一致性的参数有哪些?无疑是双一参数innodb_flush_log_at_trx_commit和sync_binlog, 这两个参数是控制 MySQL 磁盘写入策略以及数据安全性的关键参数,MySQL 为了保证 master 和 slave 的数据一致性,就必须保证 binlog 和 InnoDB redo 日志的一致性。 参数说明如下: innodb_flush_log_at_trx_commit(redo)
sync_binlog (binlog)
那么如何保证 binlog 和 InnoDB redo 日志的一致性,MySQL 使用内部分布式事物来保证一致性,MySQL 在 prepare 阶段会生成 xid,xid 会写入prepare log中,也会写入到binlog中,当恢复时会对比此事务的xid在两个文件中是否都有,如果都存在该xid对应的事物会提交,反之会rollback此事务,下面是几种情况分析:
总结起来说就是如果一个事物在 prepare log 阶段中落盘成功,并在 MySQL Server 层中的 binlog 也写入成功,那这个事务必定commit成功。 组提交现在回头看事务是如何提交的那张图,会发现innodb层每个事务是并行的,但是在写binlog时,MySQL Server层就变成了串行,这是因为每次提交都会去申请prepare_commit_mutex这把锁造成的,在MySQL 5.6版本中,提供了Binary Log Group Commit 也就是组提交,Group Commit分为了三个阶段。
下面是我们测试组提交的一张图,可以看到组提交的TPS高不少。 1062、1053复制错误可能DBA在使用MySQL Replication的过程中,在slave 宕机或异常时,会遇到1062等错误,大家都是使用以下方式解决。
但为什么数据会冲突呢?我们分解下复制的步骤,这里有张图很好,图片来自于网络。 我们可以看到这里有保存Replication matadata的两个文件,
如下图,如果SQL线程正在回放,回放完后,还没来的及写到Replication matadata的文件中,就宕机了,此时重启slave后,就会出现1062错误。 在MySQL 5.6中,提供了SQL/IO thread crash-safe特性。通过将relay_log_info_repository=TABLE,relay-info将信息写入到mysql.slave_relay_log_info这张表中,不但可以保证一致性(写文件变成同一事物的原子操作),还提高了写入性能。 如上图。IO thread同理,稍有不同的是 relay-log-recover 设置为1后,slave 的 IO thread 读取 events 时,会根据从 SQL thread 回放到的位置重新读取。 复制最优的参数配置上面讲了这么多,其实就是得出 MySQL Replication 的最可靠的参数配置。 master:
slave:
如何提高复制效率?MySQL 5.6提供了并行复制,但是这种并行只是基于database的。如果是基于单database的依然无法做到真正的并行回放,这个阶段很多DBA将数据库进行垂直拆分,将一个database拆分成几个database,通过设置slave_parallel_workers=n,可以进行database级别的并行复制,但对于热点业务复制延迟依然无法解决。 MySQL 5.6版本中还引入了GTID,不但降低了主从failover时,寻找filename,position的难度,更是加入到了组提交中,这也造就了MySQL 5.7版本中的Multi-Threaded Slave的出现。如下图,一组中的事务,可以并行回放。 在下图的测试中,MySQL 5.7的多线程复制极大的提升了延迟效率,在30个线程并发操作的时候还能保证平均延迟5.9秒左右,而单线程复制的延迟率基本一直在上升。 Multi-Threaded Slave 相关参数
半同步我们都知道,默认的 MySQL Replication 复制为异步模式,异步也就说明会有丢失数据的可能性,MySQL在5.5版本中提供了 semi-sync replication,也就是半同步,但半同步只能说减少数据丢失的风险,所以在 MySQL 5.7版本中,MySQL 提供了 lossless semi-sync replication,也就是无损复制,可最低限度的减少数据丢失(无损复制会和半同步一样在出问题时会切换为异步复制)。 在半同步中,至少有一个Slave节点收到binlog后再返回,不能完全避免数据丢失,超时后,切回异步复制。在事物提交的过程中,在InnoDB层的 commit log 阶段后,Master 节点需要收到至少一个Slave节点回复的ACK后,才能继续下一个事物。 无损复制在无损复制中,master把binlog发送给slave,只有在slave把binlog写到本地的relay-log里,master才会将事务提交到存储引擎层,然后把请求返回给客户端,客户端才可以看见刚才提交的事务。在一个事物提交的过程中,在MySQL Server 层的 binlog阶段后,Master节点需要收到至少一个Slave节点回复的ACK后,才能继续下一个事物。 半同步复制与无损复制的对比ACK的时间点不同
主从数据一致性
半同步相关参数
半同步相关事件统计
multi-source然而在MySQL 5.7版本中,提供了多源复制,多源复制的出现对于分库分表的业务提供了极大的便利,目前我们已经部署了多套多源复制供统计使用。 如上图,多源复制采用多通道的模式,和普通的复制相比,就是使用FOR CHANNEL进行了分离。
上面我们也说到,为了提高复制效率,很多DBA会根据业务进行DB拆分,但拆分后又面临一个新的问题,就是join,join绝对是关系型数据库中最常用一个特性,然而在分布式的环境中,join是最难解决的一个问题,使用多源复制就能很好的解决这个问题。 如果数据库,表名一致如何使用多源复制?,其实只要解决了数据冲突的问题就可以使用。 如上图的分库分表架构,可以使用以下参数实现奇偶插入的方 |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|