生活中所受的苦,终会以一种形式回归!
在实际的生产环境中,由单台MySQL作为独立的数据库是完全不能满足实际需求的,无论是在安全性,高可用性以及高并发等各个方面
因此,一般来说都是通过集群主从复制(Master-Slave)的方式来同步数据,再通过读写分离(MySQL-Proxy)来提升数据库的并发负载能力进行部署与实施
总结MySQL主从集群带来的作用是:
说到主从同步,离不开binlog这个东西,先介绍下binlog吧
binlog是什么?有什么作用?
用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。可以简单理解为记录的就是sql语句
binlog 是 mysql 的逻辑日志,并且由 Server
层进行记录,使用任何存储引擎的 mysql 数据库都会记录 binlog 日志
在实际应用中, binlog 的主要使用场景有两个:
日志格式
binlog 日志有三种格式,分别为 STATMENT 、 ROW 和 MIXED
在 MySQL 5.7.7 之前,默认的格式是 STATEMENT , MySQL 5.7.7 之后,默认值是 ROW
日志格式通过 binlog-format
指定。
我们还可以通过mysql提供的查看工具mysqlbinlog查看文件中的内容,例如
mysqlbinlog mysql-bin.00001 | more
binlog文件大小和个数会不断的增加,后缀名会按序号递增,例如mysql-bin.00002
等。
可以看到mysql主从复制需要三个线程:master(binlog dump thread)、slave(I/O thread 、SQL thread)
基本过程总结
master-info
文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容。relay-log.info
中记录当前应用中继日志的文件名和位置点以便下一次数据复制。在MySQL 5.6版本之前,Slave服务器上有两个线程I/O线程和SQL线程。
I/O线程负责接收二进制日志,SQL线程进行回放二进制日志。如果在MySQL 5.6版本开启并行复制功能,那么SQL线程就变为了coordinator线程,coordinator线程主要负责以前两部分的内容
上图的红色框框部分就是实现并行复制的关键所在
这意味着coordinator线程并不是仅将日志发送给worker线程,自己也可以回放日志,但是所有可以并行的操作交付由worker线程完成。
coordinator线程与worker是典型的生产者与消费者模型。
不过到MySQL 5.7才可称为真正的并行复制,这其中最为主要的原因就是slave服务器的回放与主机是一致的即master服务器上是怎么并行执行的slave上就怎样进行并行回放。不再有库的并行复制限制,对于二进制日志格式也无特殊的要求。
为了兼容MySQL 5.6基于库的并行复制,5.7引入了新的变量slave-parallel-type
,其可以配置的值有:
下面分别介绍下两种并行复制方式
按库并行
每个 worker 线程对应一个 hash 表,用于保存当前正在这个worker的执行队列里的事务所涉及到的库。其中hash表里的key是数据库名,用于决定分发策略。该策略的优点是构建hash值快,只需要库名,同时对于binlog的格式没有要求。
但这个策略的效果,只有在主库上存在多个DB,且各个DB的压力均衡的情况下,这个策略效果好。因此,对于主库上的表都放在同一个DB或者不同DB的热点不同,则起不到多大效果
组提交优化
该特性如下:
具体是如何实现的:
commit_id
,下一组为commit_id+1
,该commit_id
会直接写到binlog中;commit_id
的事务会被分发到多个worker并行执行,直到这一组相同的commit_id
执行结束后,coordinator再取下一批。更详细内容可以去官网看看:https://dev.mysql.com/doc/refman/5.7/en/replication-options-slave.html
下面开始介绍主从延时
主从延迟是怎么回事?
根据前面主从复制的原理可以看出,两者之间是存在一定时间的数据不一致,也就是所谓的主从延迟。
我们来看下导致主从延迟的时间点:
那么所谓主从延迟,就是同一个事务,从库执行完成的时间和主库执行完成的时间之间的差值,即T3-T1。
我们也可以通过在从库执行show slave status
,返回结果会显示seconds_behind_master
,表示当前从库延迟了多少秒。
seconds_behind_master如何计算的?
seconds_behind_master
,也就是前面所描述的T3-T1。为什么会主从延迟?
正常情况下,如果网络不延迟,那么日志从主库传给从库的时间是相当短,所以T2-T1可以基本忽略。
最直接的影响就是从库消费中转日志(relaylog)的时间段,而造成原因一般是以下几种:
1、从库的机器性能比主库要差
比如将20台主库放在4台机器,把从库放在一台机器。这个时候进行更新操作,由于更新时会触发大量读操作,导致从库机器上的多个从库争夺资源,导致主从延迟。
不过,目前大部分部署都是采取主从使用相同规格的机器部署。
2、从库的压力大
按照正常的策略,读写分离,主库提供写能力,从库提供读能力。将进行大量查询放在从库上,结果导致从库上耗费了大量的CPU资源,进而影响了同步速度,造成主从延迟。
对于这种情况,可以通过一主多从,分担读压力;也可以采取binlog输出到外部系统,比如Hadoop,让外部系统提供查询能力。
3、大事务的执行
一旦执行大事务,那么主库必须要等到事务完成之后才会写入binlog。
比如主库执行了一条insert … select非常大的插入操作,该操作产生了近几百G的binlog文件传输到只读节点,进而导致了只读节点出现应用binlog延迟。
因此,DBA经常会提醒开发,不要一次性地试用delete语句删除大量数据,尽可能控制数量,分批进行。
4、主库的DDL(alter、drop、create)
1、只读节点与主库的DDL同步是串行进行,如果DDL操作在主库执行时间很长,那么从库也会消耗同样的时间,比如在主库对一张500W的表添加一个字段耗费了10分钟,那么从节点上也会耗费10分钟。
2、从节点上有一个执行时间非常长的的查询正在执行,那么这个查询会堵塞来自主库的DDL,表被锁,直到查询结束为止,进而导致了从节点的数据延迟。
5、锁冲突
锁冲突问题也可能导致从节点的SQL线程执行慢,比如从机上有一些select .... for update的SQL,或者使用了MyISAM引擎等。
6、从库的复制能力
一般场景中,因偶然情况导致从库延迟了几分钟,都会在从库恢复之后追上主库。但若是从库执行速度低于主库,且主库持续具有压力,就会导致长时间主从延迟,很有可能就是从库复制能力的问题。
从库上的执行,即sql_thread
更新逻辑,在5.6版本之前,是只支持单线程,那么在主库并发高、TPS高时,就会出现较大的主从延迟。
因此,MySQL自5.7版本后就已经支持并行复制了。可以在从服务上设置 slave_parallel_workers
为一个大于0的数,然后把slave_parallel_type
参数设置为LOGICAL_CLOCK
,这就可以了
mysql> show variables like 'slave_parallel%';
+------------------------+----------+
| Variable_name | Value |
+------------------------+----------+
| slave_parallel_type | DATABASE |
| slave_parallel_workers | 0 |
+------------------------+----------+
主从同步问题永远都是一致性和性能的权衡,得看实际的应用场景,若想要减少主从延迟的时间,可以采取下面的办法:
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8