0.起因
线上MySQL实例,今天报大量延时,且卡住不动。(表现为seconds_behind_master不断上涨,从库gtid不动)
同时二级从库有复制SQL进程报错
[ERROR] [MY-010584] [Repl] Slave SQL for channel '': Could not execute Update_rows event on table 「表名」; Can't find record in '「表名」', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log mysql-bin.000****, end_log_pos *******, Error_code: MY-001032
1.排查问题
排查问题时
- 确认该实例上的从库不提供线上实时业务访问(业务可以接受延时)。不需要做从库切流量动作
- 先是看了一下从库的多线程复制是database级的,开启多线程复制到logical_clock ,问题并没有恢复
-
set global slave_parallel_type=‘logical_clock’; set global slave_parallel_workers=4; start slave sql_thread;```
- 排除掉是线程数不够的原因
- 发现processlist中是在等Applying batch of row changes (update)
- 确定是卡在sql进程,再看relaylog确实持续增长800M(表示该实例写入不频繁)
- 解析relaylog 发现是普通的update语句大约有8000次左右
- 这个量级的update且是row模式,理论1分钟内就追上了。
- 查看锁datalocks,发现有大量的行数50几万,都是同一个表的
- slave的sql进程不应该有这个量级的行锁。
- 查看表结构发现这个表是无主键的表,里面大约有50几万条记录,无主键无索引
2.定位问题
通过上面的问题排查,已定位到无主键表的update 引起的复制同步报警。
- 写库上的一条update语句,用row模式传递过来是大约8000次
update 表名 set 列1=%s,列2=%s... where 列1=%s,列2=%s...
- 针对每一行的update,从库都需要一次完整的表扫描。8000次*50万,导致从库同步几乎追不上来
3.slave_rows_search_algorithms参数
针对无主键表的复制MySQL5.6以后有个参数来调整从库定位数据的方法:slave_rows_search_algorithms
参考官方文档,
- 这个参数是从三个可能选项中选出至少两项
- 1.TABLE_SCAN(表扫描),2.INDEX_SCAN(索引扫描),3.HASH_SCAN(hash定位)
- 默认是:INDEX_SCAN,TABLE_SCAN
- 一般建议在存在无主键表的复制下,设置为:INDEX_SCAN,HASH_SCAN 通常可以加快从库的同步速度
4.解决问题
针对我们的问题,做了以下处理。
- 与这个库的研发负责人,沟通无主键表需要立即增加主键的整改
- 调整slave_rows_search_algorithms参数到INDEX_SCAN,HASH_SCAN
- 在从库上查看卡住的表的结构,找到筛选度高的列,增加普通索引
- 这里不需要关注业务是否需要,单纯只是为了加快复制速度,所以加的索引未来可能会删掉
- 加索引的步骤是从库和主库分别执行
-
alter table 表名 add index idx_表名_tmp(字段); set sql_log_bin=1;```
- 实时观察data_locks和processlist防止有线上阻塞出现
- 加索引过程大约进行了2分钟,加完索引约1分钟后故障恢复
- 同时二级从库有复制SQL进程报错的,把它的change master到主库后,自行恢复
- 这个实例先前的slave_rows_search_algorithms已经被改成INDEX_SCAN,HASH_SCAN,也就是先前有dba处理过这个参数
- 但是理论上它不存在写入脏数据的可能性(开的readonly,且gitd set是正常的)
- 非常诡异的是,在加完索引和change master后,自行恢复了。(这个没整明白为啥会有报错,又为啥自行恢复)
5.补充
继续跟踪这个问题,发现这个实例是从oracle上迁到MySQL上的,所以不止这一个表没有主键。只是其他的表这次没有大量的update所以没有暴发,一起补了索引。
所以
- MySQL的表一定要有主键的,这个规范不能放松(哪怕是异构迁移过来的实例)
- 已存在的无主键表,如果造成了复制卡住,可以临时加上普通索引(不用经过业务同意,dba自行选一个列做索引,先恢复故障)
- slave_rows_search_algorithms参数,可以加快无主键表的复制速度,但是不是万能的,需要慎用。