【MySQL】5.7新特性之七
写在前面
本系列文章基于 5.7.12 版本讲述MySQL的新特性。从安装,文件结构,SQL ,优化 ,运维层面 复制,GITD等几个方面展开介绍 5.7 的新特性和功能。同时也建议大家跟踪官方blog和官方文档,以尽快知悉其新的变化。本文主要研究5.7 复制方面的改进和优化。
7.1 Lock_log 锁优化
主从复制过程中,拉取主库的binlog 的时候有一把大锁 , 在 5.7.12 之前,dump thread读取binlog event事件的时候会持有锁,最严重的是client 的写入和dump thread读取binlog 是互斥的,带来两个严重的问题
a 在MySQL中,写入与读取binlog使用的是同一把锁(Lock_log),频繁的读取binlog,会加剧Lock_log冲突,影响主库执行,进而造成TPS降低或抖动;
b 当备库数量较多时,备库拉取binlog会占用过多的带宽,影响应用的响应时间。
5.7.12 以及之后的版本MySQL对该锁机制进行优化,只有在最后一次写入log event成功之读取位点的时候才持有该锁。这项优化意味着并发读取binlog 成为可能,并且dump thread 读取binlog的时候,client可以同时写入binlog。
7.2 半同步增强
5.6 的semi sync 在一定程度上保障了主从数据的一致性和可靠性。在Semisynchronous Replication模式下,在主库上提交一个事务/event,它会等待至少一个slave通知主库,slave 已经接收到传递过来的events并写入relay log,才返回给回话层写入成功,或者直到传送日志发生超时,
而且这期间主库的会话只能等带,所以在上线semi sync复制的时候 很多人都会考虑性能的下降问题。5.7版本中MySQL对此做了极大的改善,增加了ack thread 和AFTER_COMMIT 模式。
5.6版本的半同步逻辑
5.7版本的半同步逻辑
在增加ACK thread 之后,主库提交事务之后,当前会话可以进行处理其他请求,由ack thread 来负责slave发送回来的确认,极大的提高主库的写入性能。
b 无数据丢失
5.6 版本的默认是AFTER_COMMIT 模式
AFTER_COMMIT :某个会话在主库提交事务,主库将提交的事务持久化到存储引擎和binlog并且同步给slave ,主库等待slave将接收的持久化到relay-log,并返回确认信息给主库, 一旦主库收到从库的信息就返回OK给客户端。在此期间会话是不能进行下一步操作的。
比如主库操作update t1 set val= 1 where id= 10 将val 从5修改为1 。
1 会话session1 在主库提交
update t1 set val= 1 where id= 10 ; commit;
2 主库根据二阶段提交将数据持久化到innodb和提交日志binlog
3 同步日志到 slave ,并等待slave 返回ack信息,等待的实际时间以 rpl_semi_sync_master_timeout 为准,超过该设置时间则超时,主库返回给客户端成功写入信息。
4 接收到来自slave 的ack 信息,返回成功给OK 客户端。
分析:
第四步之前,master还未收到slave 的ack 信息,此时由于事务已经提交,除了当前会话,其他会话是可以看到val= 1 。此时发生HA切换,主库服务器down或者主库实例crash
主库未接收到slave的ack信息, slave接收到日志并落盘,应用binlog 把t1. val 更新为1 ,此时业务切换到slave上能获取到一致的数据。
如果在 slave 还未接收到binlog 并且主库挂了,因为主库已经提交,此时主库t1. val 是1而从库t1. val 是5 ,主备不一致。
AFTER_SYNC (the default): 5.7 开发了新的模式,会话提在主库上提交事务,主库会记录binlog 并且同步给slave ,等待事务在slave落盘记录到relay-log中并返回ack信息。
特别强调此时事务还未commit,故其他会话是看不到修改的记录,这点和after_commited 不一样。 一旦主库收到从库的信息,主库就提交该事务并且返回OK给客户端。
比如主库操作update t1 set val= 1 where id= 10 将val 从5修改为1 。
1 会话session1 在主库提交
update t1 set val= 1 where id= 10 ; commit;
2 主库将事务写入binlog,将binlog同步给slave,不提交。
3 等待slave 返回ack信息,等待的实际时间以 rpl_semi_sync_master_timeout 为准,如果超时 则回滚该事务。
4 接收到来自slave 的ack 信息,主库进行提交并且返回成功给OK 客户端。
分析
如果在第3步等待slave ack的过程中,主库发生crash( 此时t1. val= 5) , HA 切换到slave,应用查询slave 。如果slave 接收到binlog并发送ack给master,则t1. val= 1。如果slave未接收到事务和响应主库,此时t1. val= 5,无论哪种状态,对于所有客户端数据库都是一致,事务都没有丢失。
#这里分析的不严谨,待讨论 ##
7.3 GTID功能增强
大家比较熟悉 5.6 版本的GTID功能和作用,简化复制和降低主从复制维护的难度,提高复制的可运维性,不再依赖Master的binlog文件名和文件中的位置。
但是它有很多限制,5.7版本MySQL支持对GTID做了如下改进
a 不需要重启MySQL服务器.
b 配置过程在线,整个复制集群仍然对外提供读和写的服务.
c 不需要改变复制拓扑结构.
d 可以在任何结构的复制集群中在线启用GTID功能.
在线修改GTID时,必须按照如下顺序 OFF <-> OFF_PERMISSIVE <-> ON_PERMISSIVE <-> ON ,不能跳过其中环节,比如 gtid_mode 从off 不能直接变为on,否则MySQL会进行提示。
ERROR 1788 ( HY000) : The value of @@GLOBAL. GTID_MODE can only be changed one step at a time: OFF < - > OFF_PERMISSIVE < - > ON_PERMISSIVE < - > ON. Also note that this value must be stepped up or down simultaneously on all servers. See the Manual for instructions.
这里需要对5.7版本的GTID_MODE 进行说明
OFF :不产生GTID,Slave只接受不带GTID的事务
OFF_PERMISSIVE :不产生GTID,Slave即接受不带GTID的事务,也接受带GTID的事务
ON_PERMISSIVE :产生GTID,Slave即接受不带GTID的事务,也接受带GTID的事务
ON :产生GTID,Slave只能接受带GTID的事务。
举个例子演示开启gtid
mysql> set global gtid_mode= on;
ERROR 1788 ( HY000) : The value of @@GLOBAL. GTID_MODE can only be changed one step at a time: OFF < - > OFF_PERMISSIVE < - > ON_PERMISSIVE < - > ON. Also note that this value must be stepped up or down simultaneously on all servers. See the Manual for instructions.
mysql> set global gtid_mode= OFF_PERMISSIVE;
Query OK, 0 rows affected ( 0. 00 sec)
mysql> set global gtid_mode= ON_PERMISSIVE;
Query OK, 0 rows affected ( 0. 02 sec)
mysql> set global gtid_mode= ON; 开启gtid之前 ,必须设置enforce_gtid_consistency= on
ERROR 3111 ( HY000) : SET @@GLOBAL. GTID_MODE = ON is not allowed because ENFORCE_GTID_CONSISTENCY is not ON.
mysql> set global enforce_gtid_consistency= on;
Query OK, 0 rows affected ( 0. 00 sec)
mysql> set global gtid_mode= ON;
Query OK, 0 rows affected ( 0. 01 sec)
整个过程slave 的实例不用重启,可以持续对外提供服务。是不是可以提升DBA的幸福感了呢?
7.4 多源复制
5.7 版本之前的主从复制结构一般有一主一从,一主多从,双主(双向复制)等,不支持多主一从。5.7 版本提供多主复制:新引入 channel 的概念,每个channel
就是一个slave,有各自独立的io_thread 和sql_thread ,除此之外复制的原理和 5.6 版本的主从复制原理一致。使用多源复制可以提高从库的利用率,在一定程度上解决分片数据查询统计困难的情况。
需要特别指出的是,
a 多源复制不支持文件记录binlog位点,必须启用
master_info_repository = 'TABLE';relay_log_info_repository = 'TABLE';
b 使用多源复制要避免不同的主库出现同名的库,否则在复制时会发生错误。
7.5 并行复制
在MySQL 复制机制大致原理是:slave 通过io_thread 将主库的binlog拉到从库并写入relay log,由SQL THREAD 读出来relay log并进行重放。当主库写入并发写入压力很大,也即N:1的情形,slave 会出现延迟。
MySQL 5.6 版本提供并行复制功能,slave复制相关的线程由 io_thread,coordinator_thread,worker构成,其中 coordinator_thread 负责读取 relay log,将读取的binlog event以事务为单位分发到各个 worker thread 进行执行,并在必要时执行binlog event,比如是DDL 或者跨库事务的时候。
worker_thread:执行分配到的binlog event,各个线程之间互不影响,具体worker_thread 的个数由slave_parallel_workers决定。
需要注意的是 dbname 与 worker 线程的绑定信息在一个hash表中进行维护,hash表以entry为单位,entry中记录当前entry所代表的数据库名,有多少个事务相关的已被分发,执行这些事务的worker thread等信息;
分配线程是以数据库名进行分发的,当一个实例中只有一个数据库的时候,不会对性能有提高,相反,由于增加额外的操作,性能还会有一点回退;
MySQL 5.7 版本提供基于组提交的并行复制,通过设置参数slave_parallel_workers>0 并且 global.slave_parallel_type='LOGICAL_CLOCK'启用基于并行复制。
即主库在ordered_commit中的第二阶段的时候,将同一批commit的 binlog 打上一个相同的seqno标签,同一时间戳的事务在备库是可以同时执行的,因此大大简化了并行复制的逻辑,并打破了相同 DB 不能并行执行的限制。备库在执行时,具有同一seqno的事务在备库可以并行的执行,互不干扰,也不需要绑定信息,后一批seqno的事务需要等待前一批相同seqno的事务执行完后才可以执行。这样的实现方式大大提高了slave 应用relaylog的速度。
mysql> show variables like 'slave_parallel%' ;
+ - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - +
| Variable_name | Value |
+ - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - +
| slave_parallel_type | DATABASE | # 默认是DATABASE 模式的,需要调整或者在my. cnf中配置
| slave_parallel_workers | 4 |
+ - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - +
2 rows in set ( 0. 00 sec)
mysql> STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected ( 0. 00 sec)
mysql> set global slave_parallel_type= 'LOGICAL_CLOCK' ;
Query OK, 0 rows affected ( 0. 00 sec)
mysql> START SLAVE SQL_THREAD;
Query OK, 0 rows affected ( 0. 01 sec)
启用并行复制之后查看processlist,系统多了四个线程 Waiting for an event from Coordinator .
mysql> show processlist;
+ - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + - - - - - - + - - - - - - - - - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - +
| Id | User | Host | db | Command | Time | State | Info |
+ - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + - - - - - - + - - - - - - - - - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - +
| 9 | root | localhost: 40270 | NULL | Query | 0 | starting | show processlist |
| 10 | system user | | NULL | Connect | 1697 | Waiting for master to send event | NULL |
| 31 | system user | | NULL | Connect | 5 | Slave has read all relay log; waiting for more updates | NULL |
| 32 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |
| 33 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |
| 34 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |
| 35 | system user | | NULL | Connect | 5 | Waiting for an event from Coordinator | NULL |
+ - - - - + - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + - - - - - - + - - - - - - - - - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - +
7 rows in set ( 0. 00 sec)
推荐文章
《官方文档介绍》
MySQL 5.7并行复制实现原理与调优
MySQL内核月报 2015.01
7.6 支持在线维护replication filer
5.6 以及之前的版本在需要修改复制过滤相关配置的时候必须在配置文件中修改,然后重启数据库才能生效。5.7采用了更加灵活的方式支持在线配置过滤规则。在配置过滤规则之前必须关闭 sql_thread 或者stop slave;
这里以 REPLICATE_IGNORE_DB 为例,演示在线修改和取消REPLICATE_IGNORE_DB的具体操作。
mysql> CHANGE REPLICATION FILTER REPLICATE_IGNORE_DB= ( yang) ;
ERROR 3017 ( HY000) : This operation cannot be performed with a running slave sql thread; run STOP SLAVE SQL_THREAD first
mysql> STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected ( 0. 00 sec)
mysql> CHANGE REPLICATION FILTER REPLICATE_IGNORE_DB= ( yang,youzan) ;
Query OK, 0 rows affected ( 0. 00 sec)
取消过滤规则,只需将参数设置为空即可
mysql> STOP SLAVE SQL_THREAD;
Query OK, 0 rows affected ( 0. 01 sec)
mysql> CHANGE REPLICATION FILTER REPLICATE_IGNORE_DB= ( ) ;
Query OK, 0 rows affected ( 0. 00 sec)
mysql> start SLAVE SQL_THREAD;
Query OK, 0 rows affected ( 0. 01 sec)
这里注意的是与Oracle spfile 不一样, 虽然MySQL支持在线修改但是它不支持同时写入到my.cnf文件,如果读者朋友在线修改了,请务必配置在my.cnf文件中,避免重启失效。
参考资料
[1]《异步复制官方文档》
[2]《MySQL内核月报》
[3]《MySQL 5.7 深度解析: 半同步复制技术》
[4]《MySQL 5.7 Replication 相关》
正文到此结束