默认情况下slave的io线程把从主库dump过来的位置记录在master.info文件,sql线程的执行进度
存放在relay-log.info的文件中.如果io线程把binlog传送过来了,然后再更新master.info文件,而在
更新master.info文件的过程中,slave服务器就crash掉了.这时候master.info还是老的位置,在下一次
重新启动的时候,io线程还是从master.info读取信息,所以就会导致io线程会重复拉取binlog报错的
情形.
为了保证这种情况不发生,mysql引入了sync_master_info和sync_relay_log_info两个参数.这两个
参数表示在每次接收到事件后就更新master.info和relay-log.info两个文件,使用fdatasync()这个函数
直接同步文件系统和磁盘.由于需要频繁同步文件系统和磁盘数据,设置参数为1对slave的性能影响非常大
首先把这两个参数设置为1
mysql> show global variables like '%sync%';
+-----------------------------------------+-------+
| Variable_name | Value |
+-----------------------------------------+-------+
| binlog_group_commit_sync_delay | 0 |
| binlog_group_commit_sync_no_delay_count | 0 |
| innodb_flush_sync | ON |
| innodb_sync_array_size | 1 |
| innodb_sync_spin_loops | 30 |
| sync_binlog | 1 |
| sync_frm | ON |
| sync_master_info | 1 |
| sync_relay_log | 10000 |
| sync_relay_log_info | 1 |
查看mysql进程打开的文件情况.
[root@localhost fd]# ls -l | egrep -e '47|46'
lrwx------ 1 root root 64 Apr 16 19:33 46 -> /usr/local/mysql/data/master.info
lrwx------ 1 root root 64 Apr 16 19:33 47 -> /usr/local/mysql/data/relay-log.info
对mysql进行跟踪,在主库上使用sysbench执行3000个事务.
[root@localhost ~]# strace -f -o b.out -p 11819
过滤fdatasync函数调用情况
[root@localhost ~]# cat b.out | egrep -e 'fdatasync\(47|fdatasync\(46' | wc -l
25689
由于每次都需要调用fdatasync函数,我们发现被调用了25000多次.
现在我们设置这两个参数为0的情况
sync_master_info=0
sync_relay_log_info=0
[root@localhost fd]# ls -l | egrep -e '47 -|45 -'
lrwx------ 1 root root 64 Apr 16 19:59 45 -> /usr/local/mysql/data/master.info
lrwx------ 1 root root 64 Apr 16 19:59 47 -> /usr/local/mysql/data/relay-log.info
[root@localhost ~]# strace -f -o c.out -p 13457
Process 13457 attached with 29 threads
当设置为0后,对fdatasync的调用直接为0
[root@localhost ~]# cat c.out | egrep -e 'fdatasync\(47|fdatasync\(45'
在5.7的的标准设置下
sync_master_info=10000
sync_relay_log_info=10000
这时候对fdatasync只有两次
[root@localhost ~]# cat e.out | egrep -e 'fdatasync\(47|fdatasync\(45'
14531 fdatasync(45
14531 fdatasync(45
后续又引进了把master.info和relay-log.info直接存放到数据库中以表的形式存放,
直接当成事务的一部分来进行提交.一定要是支持事务
master_info_repository=TABLE
relay_log_info_repository=TABLE
[root@localhost fd]# ls -l | grep master | grep info
lrwx------ 1 root root 64 Apr 16 20:04 24 -> /usr/local/mysql/data/mysql/slave_master_info.ibd
[root@localhost fd]# ls -l | grep relay | grep info
lrwx------ 1 root root 64 Apr 16 20:04 23 -> /usr/local/mysql/data/mysql/slave_relay_log_info.ibd
[root@localhost ~]# cat d.out | grep fsync | grep 23
13935 fsync(23
13935 fsync(23) = 0
[root@localhost ~]# cat d.out | grep fsync | grep 24
13935 fsync(24) = 0
这时候通过把这两个表当成普通的表来进行更新.并没有产生fsync或fdatasync疯长的情况出现.
结论:为了保证slave在crash时的可靠性,1,如果从库innodb_flush_trx_at_commit设置1,那么把master_info_repository和
relay_log_info_repository两个参数都设置为TABLE;2,当设置为FILE时,可以适当把两个参数调小; 3,最不可靠的情形就是
设置这两个参数为0,不过IO的性能影响也最小.