MySQL并行复制的一个坑,MySQL的并行复制多线程复

早上巡检数据库,发现一个延迟从库的sql_thread中断了。

MySQL的并行复制多线程复制MTS(Multi-Threaded Slaves)

Last_SQL_Errno: 1755
Last_SQL_Error: Cannot execute the current event group in the parallel mode. Encountered event Gtid, relay-log name ./oracle-relay-bin.000093, position 152912092 which prevents execution of this event group in parallel mode. Reason: The master event is logically timestamped incorrectly..

检查performance_schema下的replication_applier_status_by_worker表,除了GTID之外也没有更具体的信息:

 

"root@localhost:mysql3308.sock  [(none)]>select * from performance_schema.replication_applier_status_by_worker;
 -------------- ----------- ----------- --------------- ------------------------------------------------ ------------------- -------------------- ---------------------- 
| CHANNEL_NAME | WORKER_ID | THREAD_ID | SERVICE_STATE | LAST_SEEN_TRANSACTION                          | LAST_ERROR_NUMBER | LAST_ERROR_MESSAGE | LAST_ERROR_TIMESTAMP |
 -------------- ----------- ----------- --------------- ------------------------------------------------ ------------------- -------------------- ---------------------- 
|              |         1 |      NULL | OFF           | 0b961fcc-41c2-11e7-84fd-286ed488c7da:156369774 |                 0 |                    | 0000-00-00 00:00:00  |
|              |         2 |      NULL | OFF           |                                                |                 0 |                    | 0000-00-00 00:00:00  |
|              |         3 |      NULL | OFF           |                                                |                 0 |                    | 0000-00-00 00:00:00  |
|              |         4 |      NULL | OFF           |                                                |                 0 |                    | 0000-00-00 00:00:00  |
|              |         5 |      NULL | OFF           |                                                |                 0 |                    | 0000-00-00 00:00:00  |
|              |         6 |      NULL | OFF           |                                                |                 0 |                    | 0000-00-00 00:00:00  |
|              |         7 |      NULL | OFF           |                                                |                 0 |                    | 0000-00-00 00:00:00  |
|              |         8 |      NULL | OFF           |                                                |                 0 |                    | 0000-00-00 00:00:00  |
 -------------- ----------- ----------- --------------- ------------------------------------------------ ------------------- -------------------- ---------------------- 

姜承饶

既然relay_log的位置信息都有了,那就去日志里看看吧:

 

解析Binlog文件:

简称MTS:基于binlog组提交,mysql5.7默认开启binlog组提交

mysqlbinlog -v --base64-output=decode-rows oracle-relay-bin.000093 >1.sql

找到152912092位置点附近的日志:

 组提交(group commit)是MYSQL处理日志的一种优化方式,主要为了解决写日志时频繁刷磁盘的问题。组提交伴随着MYSQL的发展不断优化,从最初只支持redo log 组提交,到目前5.6官方版本同时支持redo log 和binlog组提交。组提交的实现大大提高了mysql的事务处理性能

图片 1

 

检查了一下数据库中这个表ID为14816035的数据确实是不存在的。

支持多线程复制(Multi-Threaded Slaves, 简称MTS:基于binlog组提交 不是redolog组提交,一个组提交的事务都是可以并行回放 ,因为这些事务都已进入到事务的prepare阶段,则说明事务之间没有任何冲突(否则就不可能提交)。
SQL线程就分裂为coordinator线程和worker线程,worker线程对组提交的事务进行并行回放

另外除了这条日志,其它日志的last_committed和sequence_number都为0,last_committed表示事务提交的时候,上次事务提交的编号。last_committed和sequence_number代表的就是所谓的LOGICAL_CLOCK。

为了兼容MySQL 5.6基于库的并行复制,5.7引入了新的变量slave-parallel-type,其可以配置的值有:

猜测如果手动把这条数据插入延迟从库,并且使用注入一个空事务跳过这个GTID的方法重启sql_thread,相信这个错误也能被解决。

DATABASE:默认值,基于库的并行复制方式
LOGICAL_CLOCK:基于组提交的并行复制方式

但既然带了LOGICAL_CLOCK的事务就会出错,跳过事务的方法很难保证以后不会出错。

支持并行复制的GTID
如何知道事务是否在一组中,又是一个问题,因为原版的MySQL并没有提供这样的信息。在MySQL 5.7版本中,其设计方式是将组提交的信息存放在GTID中。那么如果用户没有开启GTID功能,即将参数gtid_mode设置为OFF呢?故MySQL 5.7又引入了称之为Anonymous_Gtid的二进制日志event类型,如:

注意到这条日志的last_committed是一个异常大的值,且错误信息中有提到The master event is logically timestamped incorrectly。我怀疑是不是并行配置的问题。

mysql> SHOW BINLOG EVENTS in 'mysql-bin.000006';
------------------ ----- ---------------- ----------- ------------- -----------------------------------------------
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
------------------ ----- ---------------- ----------- ------------- -----------------------------------------------
| mysql-bin.000006 | 4 | Format_desc | 88 | 123 | Server ver: 5.7.7-rc-debug-log, Binlog ver: 4 |
| mysql-bin.000006 | 123 | Previous_gtids | 88 | 194 | f11232f7-ff07-11e4-8fbb-00ff55e152c6:1-2 |
| mysql-bin.000006 | 194 | Anonymous_Gtid | 88 | 259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000006 | 259 | Query | 88 | 330 | BEGIN |
| mysql-bin.000006 | 330 | Table_map | 88 | 373 | table_id: 108 (aaa.t) |
| mysql-bin.000006 | 373 | Write_rows | 88 | 413 | table_id: 108 flags: STMT_END_F

从库配置:

这意味着在 MySQL 5.7版本中即使不开启GTID,每个事务开始前也是会存在一个Anonymous_Gtid ,而这GTID中就存在着组提交的信息。

"root@localhost:mysql3308.sock  [(none)]>show variables like '%para%';
 ------------------------ --------------- 
| Variable_name          | Value         |
 ------------------------ --------------- 
| slave_parallel_type    | LOGICAL_CLOCK |
| slave_parallel_workers | 8             |
 ------------------------ --------------- 

LOGICAL_CLOCK

 再检查主库配置:

然而,通过上述的SHOW BINLOG EVENTS,我们并没有发现有关组提交的任何信息。但是通过mysqlbinlog工具,用户就能发现组提交的内部信息:

(root@localhost:mysql.sock) [(none)]>show variables like '%para%';
 ------------------------ ------- 
| Variable_name          | Value |
 ------------------------ ------- 
| slave_parallel_workers | 0     |
 ------------------------ ------- 

root@localhost:~# mysqlbinlog mysql-bin.0000006 | grep last_committed
#150520 14:23:11 server id 88 end_log_pos 259 CRC32 0x4ead9ad6 GTID last_committed=0 sequence_number=1
#150520 14:23:11 server id 88 end_log_pos 1483 CRC32 0xdf94bc85 GTID last_committed=0 sequence_number=2
#150520 14:23:11 server id 88 end_log_pos 2708 CRC32 0x0914697b GTID last_committed=0 sequence_number=3
#150520 14:23:11 server id 88 end_log_pos 3934 CRC32 0xd9cb4a43 GTID last_committed=0 sequence_number=4
#150520 14:23:11 server id 88 end_log_pos 5159 CRC32 0x06a6f531 GTID last_committed=0 sequence_number=5
#150520 14:23:11 server id 88 end_log_pos 6386 CRC32 0xd6cae930 GTID last_committed=0 sequence_number=6
#150520 14:23:11 server id 88 end_log_pos 7610 CRC32 0xa1ea531c GTID last_committed=6 sequence_number=7
#150520 14:23:11 server id 88 end_log_pos 8834 CRC32 0x96864e6b GTID last_committed=6 sequence_number=8
#150520 14:23:11 server id 88 end_log_pos 10057 CRC32 0x2de1ae55 GTID last_committed=6 sequence_number=9
#150520 14:23:11 server id 88 end_log_pos 11280 CRC32 0x5eb13091 GTID last_committed=6 sequence_number=10
#150520 14:23:11 server id 88 end_log_pos 12504 CRC32 0x16721011 GTID last_committed=6 sequence_number=11
#150520 14:23:11 server id 88 end_log_pos 13727 CRC32 0xe2210ab6 GTID last_committed=6 sequence_number=12
#150520 14:23:11 server id 88 end_log_pos 14952 CRC32 0xf41181d3 GTID last_committed=12 sequence_number=13
...
可以发现较之原来的二进制日志内容多了last_committed和sequence_number,last_committed表示事务提交的时候,上次事务提交的编号,如果事务具有相同的last_committed,表示这些事务都在一组内,可以进行并行的回放。

 发现主库根本就没有slave_parallel_type这项配置。想起来主库是mysql5.6了。

例如上述last_committed为0的事务有6个,表示组提交时提交了6个事务,而这6个事务在从机是可以进行并行回放的。

(root@localhost:mysql.sock) [(none)]>select version();
 ------------ 
| version()  |
 ------------ 
| 5.6.35-log |
 ------------ 

上述的last_committed和sequence_number代表的就是所谓的LOGICAL_CLOCK。先来看源码中对于LOGICAL_CLOCK的定义:

本文由澳门新萄京官方网站发布于信息数据库,转载请注明出处:MySQL并行复制的一个坑,MySQL的并行复制多线程复

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。