MySQL 5.6开始支持并行复制,只要数据跨不同的数据库即可。开启并行复制,只需要将参数slave_parallel_workers设置成大于1的值。
不过,如果在开启并行复制的时候不开启GTID,你可能会遇到很多问题。
1.跳过复制错误
当发生错误而停止复制,常用的一个手段是"暂时跳过,日后修复"。这意味着你会set global sql_slave_skip_counter=1,尽可能快地重启复制,然后使用pt-table-checksum/pt-table-sync来重新同步从库数据。
有一天,我遇到了这个问题:
mysql> show slave status; [...] Last_SQL_Error: Worker 0 failed executing transaction '' at master log mysql-bin.000017, end_log_pos 1216451; Error 'Duplicate entry '1001' for key 'PRIMARY'' on query. Default database: 'db1'. Query: 'INSERT INTO sbtest1 (id, k, c, pad) VALUES (0, 5320, '49123511666-22272014664-85739796464-62261637750-57593947547-00947134109-73607171516-11063345053-55659776318-82888369235', '11400300639-05875856680-20973514928-29618434959-69429576205')' Exec_Master_Log_Pos: 1005432
我尝试跳过该错误:
mysql> set global sql_slave_skip_counter=1; mysql> start slave;
但是还是发生错误:
mysql> show slave status; [...] Last_SQL_Error: Worker 0 failed executing transaction '' at master log mysql-bin.000017, end_log_pos 1216451; Error 'Duplicate entry '1001' for key 'PRIMARY'' on query. Default database: 'db1'. Query: 'INSERT INTO sbtest1 (id, k, c, pad) VALUES (0, 5320, '49123511666-22272014664-85739796464-62261637750-57593947547-00947134109-73607171516-11063345053-55659776318-82888369235', '11400300639-05875856680-20973514928-29618434959-69429576205')' Exec_Master_Log_Pos: 1005882
可以看到,Exec_Master_Log_Pos已经向前移动了,但是还是报相同的错误。
发生这个错误的原因是SHOW SLAVE STATUS被MTS误导了。根据文档:
从MySQL5.6.3开始,开始了并行复制后,show slave status的Exec_Master_Log_Pos是日志应用的低水位标志,表示在此之前没有未提交的事务。因为当前的实现支持在不同的数据库上以与主库上不同的顺序执行事务,所以该值不表示最近执行的事务。
因此,我的解决方法是首先检查是否有gap,处理完gap后再跳过事务。
mysql> start slave until sql_after_mts_gaps; mysql> set global sql_slave_skip_counter=1; mysql> start slave; mysql> show slave statusG Slave_IO_Running: Yes Slave_SQL_Running: Yes
解析来就是处理数据一致的问题了,使用pt-table-checksum/pt-table-sync来重新同步从库数据。
2.备份
既然不能详细show slave status的获取日志位置,这意味着从具有并行复制的从机上获取备份是很棘手的。
例如,如果你运行mysqldump --dump-slave=2获取主库的日志位置。mysqldump会首先运行stop slave,然后show slave status。停止slave就能避免产生gap么?实际上并非如此。
唯一选择是:在执行start slave until sql_after_mts_gaps之后,运行stop slave,最后执行mysqldump。这样很不方便。
GTID带来的安全
对于上面两个问题,解决方案就是使用GTID。
最后
使用GTID和MTS时一切都顺利吗?不完全是……但这将是另一篇文章的主题!