目录
1、MySQL的主从复制架构
2、主从复制架构的意义?
2.1、高可用架构
2.2、读写分离架构
从库的应用场景?
3、MySQL实现主从复制的工作原理
4、如何为MySQL搭建一套主从复制架构?
5、主从同步几种方式
5.1、异步复制方式
5.1.1、如何实现读写分离
5.1.2、异步复制问题
5.2、半同步复制方式
6、主从复制架构中的数据延迟问题,应该如何解决?
6.1、延迟
6.2、为什么会产生这个主从延迟的问题呢?
6.3、主从之间到底延迟了多少时间呢?
6.4、主从同步延迟的问题,会导致一些什么样的不良情况呢?
6.5、并行复制
7、数据库高可用:基于主从复制实现故障转移
1、MySQL的主从复制架构
聊聊MySQL主从复制的几种复制方式
主从复制架构,顾名思义,就是部署两台服务器,每台服务器上都得有一个MySQL,其中一个MySQL是master(主节点),另外一个MySQL是 slave(从节点)。
我们的系统平时连接到master节点写入数据,当然也可以从里面查询了,就跟你用一个单机版的 MySQL是一样的,但是master节点会把写入的数据自动复制到slave节点去,让slave节点可以跟 master节点有一模一样的数据
2、主从复制架构的意义?
2.1、高可用架构
高可用架构怎么做呢?一个先决条件就是主从复制架构。必须得让主节点可以复制数据到从节点,保证主从数据是一致的,万一主节点宕机,此时可以让Java业务系统连接到从节点上去执行SQL语句,写入数据和查询数据,因为主从数据是一致的,所以这是没问题的。
- 如果实现这样的一个效果,自然就实现了MySQL的高可用了,他单机宕机不影响你的Java业务系统的运行,也是有大量的问题要解决的。
- 比如主从进行数据复制时,数据不完全一致。
- 主节点宕机后,要能自动切换从节点对外提供服务,这个也需要一些中间件的支持。
2.2、读写分离架构
- 读写分离架构,也是依赖于MySQL的主从复制架构的。
- 读写分离架构:Java业务系统可以往主节点写入数据,但是从从节点去查询数据,把读写操作做一个分离,分离到两台MySQL服务器上去,一台服务器专门让你写入数据,然后复制数据到从节点,另外一台服务器专门让你查询数据:
为什么使用读写分离架构?
因为假设 MySQL单机服务器配置是8核16GB,然后每秒最多能抗4000读写请求 ,现在假设真 实的业务负载已经达到了,每秒有2500写请求+2500读请求,也就是每秒5000读写请求了,那么你觉得如果都放一台MySQL服务器,能抗的住吗?
必然不行啊!所以此时如果你可以利用主从复制架构,搭建起来读写分离架构,就可以让每秒2500 写请求落到主节点那台服务器,2500 读请求落到从节点那台服务器,用 2 台服务器来抗下你每秒 5000 的读写请求:
大部分Java业务系统都是读多写少,读请求远远多于写请求
那么接着发现随着系统日益发展,读请求越来越多,每秒可能有6000读请求了,此时一个从节点服务器也抗不下来啊,那怎么办呢?
简单! 因为MySQL的主从复制架构,是支持一主多从的,所 以此时你可以再在一台服务器上部署一个从节点,去从主节点复制数据过来,此时你就有2 个从节点了,然后你每秒 6000 读请求不就可以落到 2 个从节点上去了,每台服务器主要接受每秒3000 的读请求:
Java业务系统每秒以2500的TPS写入主库,然后主库会复制数据到两个从库,接着你每秒6000 QPS的读请求分散在两个从库上,一切似乎很完美,这就是主从复制架构的另外一个经典的应用场景,就是读写分离,通过读写分离,可以让你抗下很高的读请求。
在上述架构之下,还可以融合高可用架构进去,因为你有多个从库,所以当主库宕机时,可以通过中间件把一个从库切换为主库,此时你的Java业务系统可以继续运行,在实现读写分离的场景下,还可以同时实现高可用。
从库的应用场景?
- 比如你可以挂一个从库,专门用来跑一些报表SQL语句,那种SQL语句往往是上百行之多,运行要好几秒,所以可以专门给他一个从库来跑。
- 也可以是专门部署一个从库,让你去进行数据同步之类的操作。
3、MySQL实现主从复制的工作原理
MySQL自己在执行增删改的时候会记录binlog日志,所以这个binlog日志里就记录了所有数据增删改的操作:
然后从库上有一个IO线程,这个IO线程会负责跟主库建立一个TCP连接,接着请求主库传输binlog日志给自己,这个时候主库上有一个IO dump线程,就会负责通过这个TCP连接把binlog日志传输给从库的IO线程:
接着从库的IO线程会把读取到的binlog日志数据写入到自己本地的relay日志文件中去,然后从库上另外有一个SQL线程会读取relay日志里的内容,进行日志重做,把所有在主库执行过的增删改操作,在从库上做一遍,达到一个还原数据的过程:
MySQL主从复制的原理简单来说,你只要给主节点挂上一个从节点,从节点的IO线程就会跟主节点建立网络连接,然后请求主节点传输binlog日志,主节点的IO dump线程就负责传输binlog日志给从节点,从节点收到日志后就可以回放增删改操作恢复数据。
在这个基础之上,就可以实现MySQL 主从节点的数据复制以及基本一致,进而可以实现高可用构以及读写分离架构。
4、如何为MySQL搭建一套主从复制架构?
MySQL主从复制的原理就是主库接受增删改操作,把增删改操作binlog写入本地文件,然后从库发送请求来拉取binlog,接着在从库上重新执行一遍binlog的操作,就可以还原出一样的数据。
- 首先要确保主库和从库的server-id是不同的。
- 其次就是主库必须打开binlog功能, 必须打开binlog功能主库才会写binlog到本地磁盘,接着就可以按如下步骤在主库上执行一通操作了。
- 假设你主库都跑了一段时间了,现在要挂一个从库,那从库总不能把你主库从0开始的所有binlog都拉一遍吧!这是不对的,此时你就应该在凌晨的时候,在公司里直接让系统对外 不可用,说是维护状态,然后对主库和从库做一个数据备份和导入。
- 可以使用的mysqldump工具把主库在这个时刻的数据做一个全量备份,但是此时一定是不能允许系统操作主库了,主库的数据此时是不能有变动的。
/usr/local/mysql/bin/mysqldump --single-transaction -uroot -proot --master-data=2 -A >
backup.sql
注意, mysqldump 工具就在你的 MySQL 安装目录的 bin 目录下,然后用上述命令就可以对你主库所有的数据都做一个备份,备份会以SQL 语句的方式进入指定的 backup.sql 文件,只要执行这个 backup.sql 文件,就可以恢复出来跟主库一样的数据。
5、主从同步几种方式
5.1、异步复制方式
异步复制,就是之前讲过的那种原理,从库是异步拉取binlog来同步的,所以肯定会出现短暂的主从不一致的问题的,比如你在主库刚插入数据,结果在从库立马查询,可能是查不到的。
5.1.1、如何实现读写分离
只要你搭建出来主从复制架构,就可以 实现读写分离了。 比如可以用mycat或者sharding-sphere之类的中间件 ,就可以实现系统写入主库,从从库去读取了。
5.1.2、异步复制问题
异步的复制方式: 主库把日志写入binlog文件,接着自己就提交事务返回了,他也不管从库到底收到日志没有。
那万一此时要是主库的binlog还没同步到从库,结果主库宕机了,此时数据不就丢失了么?即使你做了高可用自动切换,一下子把从库切换为主库,但是里面是没有刚才写入的数据的,所以这种方式有问题的。
5.2、半同步复制方式
一般来说搭建主从复制,都是采取半同步的复制方式的。
半同步:主库写入数据,日志进入binlog之后,起码得确保 binlog日志复制到从库了,你再告诉客户端说本次写入事务成功了。这样起码主库突然崩了,之前写入成功的数据的binlog日志都是到从库了,从库切换为主库,数据也不会丢的,这就是所谓的半同步的意思。
半同步复制,有两种方式
- 第一种叫做AFTER_COMMIT方式:主库写入日志到binlog,等待binlog复制到从库了,主库就提交自己的本地事务,接着等待从库返回给自己一个成功的响应,然后主库返回提交事务成功的响应给客户端。
- 另外一种MySQL 5.7默认的方式,主库把日志写入binlog,并且复制给从库,然后开始等待从库的响应,从库返回说成功给主库了,主库再提交事务,接着返回提交事务成功的响应给客户端。
总而言之,这种方式 可以保证每个事务提交成功之前,binlog日志一定都复制到从库了,所以只要事务提交成功,就可以认为数据在从库也有一份了,那么主库崩溃,已经提交的事务的数据绝对不会丢失的。
一般来说主从复制都建议做成半同步复制,因为这样配合高可用切 换机制,就可以保证数据库有一个在线的从库热备份主库的数据了,而且主要主库宕机,从库立马切换为主库,数据不丢失,数据库还高可用。
6、主从复制架构中的数据延迟问题,应该如何解决?
6.1、延迟
就是说主库可能你都写入了100 条数据了,结果从库才复制过去了50 条数据,那么从库就比主库落后了 50 条数据。
6.2、为什么会产生这个主从延迟的问题呢?
主库是多线程并发写入的,所以主库写入数据的速度可能是很快的,但是从库是单个线程缓慢拉取数据的,所以才会导致从库复制数据的速度是 比较慢的。
6.3、主从之间到底延迟了多少时间呢?
一个工具来进行监控,比较推荐的是perconatoolkit工具集里的 pt-heartbeat 工具,他会在主库里创建一个 heartbeat 表,然后会有一个线程定时更新这个表里的时间戳字段,从库上就有一个monitor 线程会负责检查从库同步过来的 heartbeat 表里的 时间戳。把时间戳跟当前时间戳比较一下,其实就知道主从之间同步落后了多长时间了,关于这个工具的使用,
6.4、主从同步延迟的问题,会导致一些什么样的不良情况呢?
读写分离架构,写都往主库写,读都从从库读,那么会不会系统刚写入一条数据到主库,接着代码里立即就在从库里读取,可能此时从库复制有延迟,你会读不到刚写入进去的数据!
- 没错,就是这个问题,这是我们之前也经常会遇到的一个问题。
- 另外就是有可能你的从库同步数据太慢了,导致你从库读取的数据都是落后和过期的,也可能会导致你的系统产生一定的业务上的bug。
所以针对这个问题,首先你应该做的,是 尽可能缩小主从同步的延迟时间 ,那么怎么做呢?其实就是 让从库也用多线程并行复制数据就可以了,这样从库复制数据的速度快了,延迟就会很低了 。
6.5、并行复制
- MySQL 5.7就已经支持并行复制了,可以在从库里设置slave_parallel_workers>0,然后把 slave_parallel_type设置为logical_clock,就ok了。
- 另外,如果你觉得还是要求刚写入的数据你立马强制必须一定可以读到,那么此时你可以使用一个办法,就是在类似MyCat或者Sharding-Sphere之类的中间件里设置强制读写都从主库走,这样你写入主库的数据,强制从主库里读取,一定立即可以读到的。
总体而言就是这样了,大家在落实读写分离架构的时候,要注意一下复制方式,是异步还是半同步?
- 如果说你对数据丢失并不是强要求不能丢失的话,可以用异步模式来复制,再配合一下从库的并行复制机制。异步模式+从库并行复制
- 如果说你要对MySQL做高可用保证数据绝对不丢失的话,建议还是用半同步机制比较好一些,同理最好是配合从库的并行复制机制。半同步机制+从库并行复制
7、数据库高可用:基于主从复制实现故障转移
高可用:如果数据库突然宕机了一台机器,比如说主库或从库宕机,那么数据库还能正常使用吗?
- 如果从库宕机了影响并不是很大,因为大不了就是让所有的读流量都从主库去读就可以了。
- 如果主库宕机了呢?那就真的麻烦了,因为主库一旦宕机,你就没法写入数据了,从库毕竟是不允许写入的,只允许读取。
所以有没有一种办法,可以在主库宕机之后,就立马把从库切换为主库呢,然后所有人都对从库切换为的主库去写入和读取呢?如果能实现这样的一个效果,那数据库不就实现高可用了吗?没错,就这么简单,这就是数据库的高可用架构。
一般生产环境里用于进行数据库高可用架构管理的工具是MHA,也就是Master High Availability
Manager and Tools for MySQL,是日本人写的,用perl脚本写的一个工具,这个工具就是专门用于监 控主库的状态,如果感觉不对劲,可以把从库切换为主库。
这个MHA 自己也是需要单独部署的,分为两种节点,一个是 Manager 节点,一个是 Node 节点, Manager节点一般是单独部署一台机器的, Node 节点一般是部署在每台 MySQL 机器上的,因为 Node 节点得通过解析各个MySQL 的日志来进行一些操作。 Manager节点会通过探测集群里的 Node 节点去判断各个 Node 所在机器上的 MySQL 运行是否正常,如果发现某个Master 故障了,就直接把他的一个 Slave 提升为 Master ,然后让其他 Slave 都挂到新的Master上去,完全透明。