0.引言

随着业务场景的深入和请求量的剧增,单库实现读写越来越趋近瓶颈,于是我们想到搭建主从库,主库负责写,从库负责读,从而实现读写分离,提高查询效率。

但是主从库之间的数据如何同步呢?很明显我们写入数据是只能通过主库操作的,因为我们要求的是主库负责写,从库负责读。我们知道binlog可以实现数据的备份和同步,那么我们是否可以通过它来实现主从同步呢?这就是我们接下来要讨论的了

1. 主从同步原理

1.1 基于binlog的主从同步原理

在正式开始讲解实操前,我们需要先了解其原理,否则只能做到知其然,而不知其所以然

什么是bin log?
bin log是我们实现主从同步的核心,同时也是我们实现数据备份、数据同步的基础,因此理解bin log是必须的。bin log本身其实就是一个二进制的日志文件,它用于记录数据表结构变化、数据变化。但是不会记录查询等操作,因为查询操作本质上不会引起数据变化。

binlog默认是关闭的,因为其本身的数据记录是会额外消耗性能的,因此我们如果不需要数据备份、同步。那么也不需要开启bin log。

binlog有三种记录模式:

(1)ROW: 行记录形式,会记录每一行的数据变化情况。优点是记得细,能够重现实现数据修改细节。缺点是会产生大量日志,消耗性能

(2)STATEMENT:状态记录形式,会记录每一条执行的SQL,然后通过SQL重放来实现数据同步。优点是节约资源,产生日志量会少很多,缺点是某些情况会导致数据不一致,比如执行的sql中

(3)MIXED:混合模式,一般情况使用STATEMENT,当STATEMENT不能满足的则自动切换为ROW进行记录

我们用一个例子来让大家理解ROW和STATEMENT的区别:

比如我现在执行的操作是 update user set level=5 where age>30。满足age>30的数据有10W条。那么statement模式记录的日志就是update user set level=5 where age>30,而row模式记录的日志则是
update user set level=5 where id=xxx1;
update user set level=5 where id=xxx2;

update user set level=5 where id=xxxN;
这里的xxxN就是age>30的行数据的id。也就是说它按照每行单独去记录变化情况

看到这里大家可能会觉得,那我就用MIXED呗,但是很多情况下,因为我们要实现主从同步,要保重主从库数据的一致性,必须要求使用ROW,才能完全体现数据变化的日志细节。

在了解了binlog之后,我们再来详细谈谈主从同步的原理细节

(1)主库将数据的变化写入到binlog中

(2)从库定期检测binlog文件是否有发生变化(检测是不需要读取文件详细内容的,可以通过文件最近修改时间和Etag来实现),如果有变化则开启一个IO线程来获取主库binlog数据

(3)同时主库会为每个IO线程启动一个dump线程,用于先IO线程发送二进制事件(也就是binlog日志数据)。发送获取的数据并不会直接给到从库进行重放,而是先放到一个中继日志(relay log)中,然后从库再从中继日志读取数据,进行重发,从而实现数据同步

(4)执行完成后,IO线程和dump线程进行睡眠状态,等待下一次数据同步再被唤醒

想象一下,数据同步过程中为什么需要中继日志,而不是让从库读取后直接重发?

中继日志的存在的目的是什么呢?这里大家发挥出自己的想象,结合以往我们所了解到的中间文件的作用,我们可以首先有一个很常见的作用:

(1)缓冲!让数据先放到中继文件中,攒够一波之后再统一处理,这样能减少IO,提高效率,这是很多中间文件的作用,但是并不是这里中继文件的作用!!!为什么?因为我们要求实时同步,等不了~ 所以攒够一波再处理的概念肯定是不通过的

(2)解耦!这才是中继文件真正的作用。我们利用发证法,假如没有中继日志,那么这个线程很明显要处理一条龙的服务,从读取binlog到重放binlog,这个操作会让这个线程很容易阻塞,因为重发sql时可能会涉及锁表、锁行的操作,不可避免的会造成一些延迟,因此我们读binlog的时候就不能重发,先将binlog实时同步过来,然后再单开一个SQL线程来重放binlog,这才是正确的处理方式。因此我们需要一个日志来帮我们先把同步的binlog记录一下,SQL线程就可以放心的做自己的重放工作,数据同步完成后中继日志会被删除。


了解到这里,相信大家对主从同步的原理已然明了,最终咱们总结下这其中的几个关键词:bin log,relay log,io 线程,dump 线程,sql 线程,如果你能够解释出这些关键词的作用,说明你已经掌握其原理过程。

但是还有一个问题,咱们还没解决:

主从同步的延迟问题:

(1)主库在记录binlog时是顺序写,效率很高,而从库的SQL线程再重放binlog时,却并不是顺序的,而是随机的。

这里要理解为什么是随机的而不是顺序的?

这里的顺序和随机指的是磁盘IO的读写顺序和随机。因为写入binlog时,是预先申请好磁盘空间的,其空间是连续的,因此写入的binlog在磁盘物理位置上是挨在一起的,即是顺序的。而重发binlog时,相当于我们重新执行sql,其sql操作的数据存放位置基本上是不可能在磁盘中连续的,也就是说起存放位置随机分布,因此我们说是随机的。随机的读写相比较于顺序的读写所需耗费的时间肯定更多

(2)从库SQL线程在重放binlog时,当同时有查询操作出现时,可能会出现锁表、锁行等锁操作,那么就需要等待锁释放的时间,而SQL线程又是单线程的,IO线程依旧在同步binlog,SQL线程这边还在等待着,延迟自然而然就产生了

那么怎么解决延迟问题呢?

首先我们要把握问题发生且我们能够干预的关键点:

从库同步的慢,从而导致了延迟,同步慢的原因:一是同步时有查询操作或者同步本身的操作产生了锁竞争;二是服务器的本身性能问题,我们知道服务器性能越高的,各方面的执行效率肯定越高,基于以上两点,我们提出以下解决方案:

(1)从库使用更好的服务器,这样从库处理的速度更快,则延迟更小

(2)部署一主多从,减少从库的读取压力,提高查询效率,减少锁竞争,从而减少同步延迟

(3)使用缓存数据库,如redis,减少读压力

(4)多主多从,从业务上拆分成多个库,并且将各个库放到不同的服务器上,从而减少单库同步的压力

(5)部署集群,减少压力

以上的解决方案当然都是需要增加服务器成本的,那么有没有从根本上解决这个延迟问题的方案呢?这就是mysql在5.7版本后做出的优化了,也就是我们下面要讨论的MTS主从同步原理

1.2 MTS主从同步原理

MTS:Multi-Threaded Slave,并行复制,实际上早在mysql5.6版本时就有基于库的并行复制,但是5.6版本的基于库的并行复制的性能并不高,当只有一个库时,其性能甚至还不如单线程,因此5.7版本时,做出了优化,推出了真正的并行复制

MTS的核心概念在于多线程并行重放binlog,但是并不是所有的binlog都能并行重放,有些操作可能涉及锁竞争,那么就不能并行执行。

MTS中除了SQL线程,还创建了多个WORK线程,IO线程不断接收bin log,写入到relay log中,SQL线程读取relay log,并且判断哪些事件可以并行回放,哪些只能串行回放。并行回放的会分发给WORK线程并行回放。串行回放的就由SQL线程自己回放。

那么如何判定哪些事件可以并行回放?

通过组提交来实现,即对事务进行分组,我们认为一个组提交的事务都是可以并行回放的,那么怎么判定事务可以处于同一个组呢?那就是看主库中事务执行时,是否能够同时提交成功,或者说同时处于prepare阶段的所有事务,都是可以同时提交的

这里需要大家了解mysql事务两阶段提交的流程,简单来说就是一个事务提交完成是需要经历两个阶段的,事务执行,将数据更新到内容后,会先写入redo log,这时事务处于prepare状态,再写入bin log,然后提交事务,并将redo log标注为commit状态,这样整个事务才算提交完成。经历了prepare,commit两个阶段

只要能同时处于prepare状态的事务,说明事务间是没有锁竞争的,那么就是可以并行执行的,同时也是可以并行回放的。如果有锁竞争的,那么该事务肯定要等待竞争事务先执行完,释放锁后才能执行,也就不可能同时处于prepare状态

所以我们接下来要解决的问题就是:

1、如何知道哪些事务处于prepare状态?

mysql5.7引入了两个变量

(1)sequence_number: 序列号,每个事务对应一个,顺序增长,当事务提交后便会得到自己的sequence_number

(2)last_committed: 表示事务提交时,上次事务提交的编号,事务进入prepare阶段后,会将自己的last_committed更新为上次提交事务的sequence_number,这样有相同last_committed的事务就是同一组。

这两个变量都会记录到bin log中,并且其作用域是文件范围内,也就是说换了一个bin log文件,其值就会从0开始计算。于是乎通过last_committed我们也就知道了哪些事务是同一组的。

2、在binlog中如何标注哪些事务是同一组的?

其实我们上面已经讲到了,是通过last_committed信息来标注,但这里我们要拓展一下,mysql5.7中将sequence_number和last_committed信息属于组提交信息,组提交信息是存放到GTID事件中的,每个事务会有自己的GTID事件。

GTID默认是关闭的,如果关闭时会讲组提交信息存放到匿名GTID事件中(Anonymous_Gtid),如果开启了,就会存储到每个事务自己的GTID事件中,每个事务执行前都会添加一个GTID事件,用于记录当前的全局事务ID

MTS并发复制流程

在了解了并发复制的原理后,我们再来整体的梳理一遍其流程:

(1)主库将数据的变化写入到binlog中

(2)从库定期检测binlog文件是否有发生变化,如果有变化则开启一个IO线程来获取主库binlog数据

(3)同时主库会为每个IO线程启动一个dump线程,用于先IO线程发送二进制事件(也就是binlog日志数据)。发送获取的数据并不会直接给到从库进行重放,而是先放到一个中继日志(relay log)中

(4)从库的SQL线程从relay log中读取事务后,会获取该事务的组信息,拿到sequence_number和last_committed

(5)从库会记录已经执行了的事务的sequence_number的最小值,将其存放到low water mark变量中,简称lwm

(6)lwm与取出事务的last_committed比较,如果last_committed比lwm更小,说明取出事务与当前执行组为同组(本组事务的sequence_number的最小值肯定大于last_committed)。则SQL线程会找到一个空闲的WORK线程,如果有空闲的,就会直接重放这个事务,如果没有空闲的,SQL线程就会处于等待状态,直到有一个空闲的WORK线程为止。

(7)如果last_committed等于大于lwm,则说明取出事务与当前执行组不是同一组,则取出事务需要等待。

如下图所示,当获取到事务4时,因为已经执行的事务的最小sequence_number是3,则lwm是3
而事务4的last_committed为3,是等于lwm的,则知道事务3和事务4不是一组

当继续执行到事务5时,因为已经执行过事务4了,则lwm=4,而事务5的last_committed=3,小于lwm,则事务5与事务4同组,可以并发复制

2. 主从同步实操

了解完主从同步的原理后,我们来实际演示下配置流程

2.1 环境准备

首先这里需要准备两台mysql服务器,一台作为主库,一台作为从库,我这里选用mysql8.0。并且创建一些数据库和表,添加一些数据进去作为同步测试

2.2 实操

1、因为是基于binlog的,需要在主从库都开启binlog,并且开启主库的GTID,修改主库配置文件

sudo vim /etc/my.cnf

修改内容

log-bin=mysql-bin #二进制文件名称
binlog-format=ROW  #二进制日志格式
server-id=1     #要求各个服务器的id必须不一样gtid_mode=ON # 开启GTID
enforce_gtid_consistency=ON
log_slave_updates=ON

2、重启主库

service mysqld restart

3、查询binlog是否开启成功,登陆主库执行

show master status;

4、给连接主库进行数据同步的账号赋权,登陆主mysql执行:

grant replication slave on *.* to 'root'@'%';
# 刷新权限
flush privileges;

5、修改从库mysql配置文件

sudo vim /etc/my.cnf

修改内容

log-bin=mysql-bin # 开启bin log,配置binlog文件名
binlog-format=ROW  #二进制日志格式
server-id=2     #要求各个服务器的id必须不一样gtid_mode=ON # 开启GTID
enforce_gtid_consistency=ON
log_slave_updates=ONslave-parallel-type=LOGICAL_CLOCK # 开启MTS相关配置,设置为LOGICAL_CLOCK实现更小粒度的并行复制
slave-parallel-workers=16 # work线程数
slave_pending_jobs_size_max = 2147483648
slave_preserve_commit_order=1 # 保证事务按照relay log记录的顺序回放,配合LOGICAL_CLOCK使用
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

6、重启从库

service mysqld restart

7、声明主库,登陆从库执行:

# 登陆
mysql -uroot -p123456
#连接主服务器
change master to master_host='192.168.244.23',master_user='root',master_password='123456',master_port=3306,master_log_file='mysql-bin.000001',master_log_pos=157;
#启动slave
start slave;

8、查看从库状态

# 表格形式输出,适合在数据库连接工具中使用
show slave status;
# 行形式输出,适合在命令行窗口中使用
show slave status\G;

这里发现报错:Authentication plugin 'caching_sha2_password' reported error

根据报错信息来看是校验模式设置为了caching_sha2_password,我们登陆主库,查看一下

SELECT plugin FROM mysql.`user` where user = 'root';


果然是,修改其为mysql_native_password即可,执行

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';

同时因为我这里从库是根据主库服务器克隆来的,所以会导致两个mysql的uuid一致,因此也需要再更改一下,修改从库auto.cnf配置文件:

# 进入mysql安装目录
cd /var/lib/mysql
vim auto.cnf

将uuid修改得与之前不一致即可

修改完重启mysql

其次还需要注意,如果你之前没有开启GTID,中间产生了一些事务,而后续又开启了GTID,非GTID事务和GTID事务之间是不能同步的,这时就需要你将binlog的同步位置,调整到开启GTID之后

# 查询当前binlog位置,主库中执行
show master status;
# 从库中修改同步位置
stop slave;
change master to master_log_file='mysql-bin.000003',master_log_pos=197;
start slave;
# 查询slave状态
show slave status\G;

如图所示无报错即可

9、修改主库数据,任意修改了一条数据

10、查看从库对应的表数据


同步成功!!

总结

本期的分享就到此结束了,一定要亲自动手实操试试,只有自己尝试,才会发现更多的问题,才能掌握的更加牢靠

关注公众号 Elasticsearch之家,优先掌握更多内容

【mysql进阶】MTS主从同步原理及实操指南(七)相关推荐

  1. MYSQL管理之主从同步管理

    原文地址:MYSQL管理之主从同步管理 作者:飞鸿无痕 MYSQL管理之主从同步管理 MYSQL主从同步架构是目前使用最多的数据库架构之一,尤其是负载比较大的网站,因此对于主从同步的管理也就显得非常重 ...

  2. MySQL的主从复制主从同步

    MySQL 主从复制概念 MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点.MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数 ...

  3. 企业实战|Mysql不停机维护主从同步

    转载来源 :企业实战|Mysql不停机维护主从同步 : https://mp.weixin.qq.com/s/CQFmFhtRMFsESofDpTOvUA 实战环境: Mysql-5.7 Xtraba ...

  4. mariadb mysql同步_MariaDB(mysql)之主从同步

    一.主从同步的作用 1.数据分布 2.负载均衡(load balancing) 4.高可用性(high availability)和容错 二.主从同步原理 mysql(MariaDB)的主从复制其实很 ...

  5. pika主从同步原理

    pika主从同步 主要为了分析探索一下pika是如何实现主从同步的,pika的主从同步的原理与redis的同步方案还不相同,本文主要是为了分析其主从同步的相关流程(pika基于3.4版本). pika ...

  6. 基于 CentOS Mysql 安装与主从同步配置详解

    CentOS Mysql 安装 Mysql (Master/Slave) 主从同步 1.为什么要使用主从同步 1.如果主服务器出现问题,可以快速切换到从服务器提供的服务 2.可以在从服务器上执行查询操 ...

  7. mysql数据库的主从同步(主服务器存在内网IP)

    1 分别在两台服务器上安装系统和mysql数据库 主服务器WIN2008R2,主服务器虚拟机和从服务器上是centos 7系统,并在centos 7系统安装mysql 5.7 本文中的两台服务器的IP ...

  8. mysql数据库的主从同步,实现读写分离

    目录 前言 1 分别在两台centos 7系统上安装mysql 5.7 2 master主服务器的配置 2.1 配置文件my.cnf的修改 2.2 创建从服务器的用户和权限 2.3 重启mysql服务 ...

  9. MySQL主从复制与读写分离配置及实操

    MySQL主从复制与读写分离 一.MySQL主从复制 1.复制类型 2.工作过程 二.MySQL读写分离 1.定义 2.存在意义 3.作用时间 4.原理 5.类型 基于程序代码内部实现 基于中间代理层 ...

最新文章

  1. 2021-2027年中国一次成型光学玻璃行业市场分析及投资潜力研究报告
  2. 代码结构中 Dao,Service,Controller,Util,Model 是什么意思,为什么划分?
  3. 架设HmailServer邮件服务器以及webmail
  4. YTU 2903: A--A Repeating Characters
  5. Redis缓存持久化:RDB持久化和AOF持久化
  6. android支付宝余额怎么做,android实现类似于支付宝余额快速闪动的效果
  7. MySQL保存计算结果_在数据库中保存计算结果如何对应到相应的工程文件
  8. Linux上RandomAccessFile访问FTP文件出错
  9. 耦合器滤波器衰减器无源器件自动化测试软件系统,纳米NSAT-1000
  10. 浪潮信息m6服务器性能,展现强劲性能,浪潮M6服务器为什么能刷新SPEC多项记录...
  11. J2ME 2D小游戏入门之旅(五) 实现爆炸效果、并加入道具导弹(转)
  12. APP - 朋友圈广告原来是可以关掉的
  13. 数据分析综述:一文带你详细了解自动驾驶技术
  14. [CISCN2019 华东南赛区]Web4
  15. html设置打印尺寸,打印尺寸及常用格式尺寸设置 css
  16. 如何解决Namespace declaration statement has to be the very first statement or after any declare call
  17. 昨日一宿春雨下,我想永远是清明
  18. 会中切换网络总掉线?腾讯会议用这种方案让你好好开会
  19. OpenCV图像颜色反转算法
  20. 自动驾驶 | 传感器融合–自动驾驶的关键技术

热门文章

  1. Android Studio项目在安卓手机上模拟
  2. 什么是交叉熵啊?| 小白深度学习入门
  3. windows使用es的客户端es-head
  4. AA和AAA台灯区别大吗?护眼台灯选哪个品牌比较好
  5. 如何制作驱动程序安装包
  6. Machine Learning Basics(1)
  7. win10系统可以做服务器系统吗,win10系统可以做云盘服务器吗
  8. 申请微信公众号的一些流程和注意
  9. 黑马程序员HTML+CSS学成在线项目
  10. 云服务器使用感受迥漣稅蒟羺怸遯潲佧罧障煓茹棚億辖嗔徟嚼囙