背景: 生产环境出现主从同步的故障, 出现的错误为HA_ERR_KEY_NOT_FOUND, 错误码为1032,检查主从数据没有出现缺失, 表结构和数据都完全一致, 经过排查问题是在于主从同步的配置,这里以示例做模拟重现,逐步分析定位出具体原因。
1、升级后, 主从同步出现故障, 错误码为1032,进入从节点, 查看主从同步状态
show slave statusG
出现如下错误:
2、查看具体的错误信息
select * from performance_schema.replication_Applier_status_by_worker;
可以看到错误和事务序号信息:
这里提示错误的binlog文件为binlog.00025, 下面需要分析此日志文件。
1、首先对binlog日志进行分析
① 解析主节点的binlog日志
/usr/local/MySQL/bin/mysqlbinlog --no-defaults -v /datadir_3306/log/binlog.000025 --base64-output=decode-rows > bin.000025.txt
根据事物信息,搜索解析后的bin.000025.txt文件:
@1对应的是表的第一个字段, @2是第二个字段,根据条件信息, 去从库里面查找, 发现是可以找到对应的记录。
② 查看表结构信息
生产的这次升级, 是去除了原有的ID自增主键, 保留了唯一索引, 未升级之前是可以正常同步, 于是要在本地验证下, 这种表结构是否可以正常同步。
2、本地主从同步验证
本地搭建的主从同步环境, 采用默认的主从同步配置,验证发现, 无论是新增删除、还是对表结构复原,删除主键ID,再插入数据, 都是可以正常同步。
这里有个特殊之处, 是在于应用程序的写入, 是采用insert into .... on duplicate key update 操作,也就是不存在新增数据, 存在则根据唯一索引更新数据, 但经过实际多次的写入验证, 无论是新增还是更新, 都能够正常进行同步。
3、最后检查生产环境的主从同步配置
问题原因可能出现在主从同步配置上, 为了能够重现, 找出真正原因, 拿到生产的配置, 重新再做主从同步验证。 生产的主从同步配置:
sync_binlog=1
gtid_mode=on
enforce_gtid_consistency=1
log_bin=/mydata/3306/log/bin.log
log_bin_index=/mydata/3306/log/bin.index
log_slave_updates=1
binlog_format=ROW
binlog_rows_query_log_events=1
relay_log=/mydata/3306/log/relay-bin.log
relay_log_index=/mydata/3306/log/relay-bin.index
relay_log_info_file=/mydata/3306/log/relay-log.info
relay_log_recovery=1
slave_skip_errors=ddl_exist_errors
slave-rows-search-algorithms='INDEX_SCAN,HASH_SCAN'
innodb_flush_log_at_trx_commit=1
max_binlog_size=100M
skip-slave-start=1
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=8
slave_preserve_commit_order=1
slave_transaction_retries=128
# 采用半同步模式
plugin_dir='/usr/local/mysql/lib/plugin'
plugin_load="validate_password.so;rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so"
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=3000
rpl_semi_sync_slave_enabled=1
这份配置生产一直运行并未出现问题, 初步检查,也没发现什么问题,按此配置更新
1)停止主从同步
stop slave;
2)重置主从同步
reset slave;
3)查看并记录主节点的同步偏移量
show master statusG
日志文件为binlog.000024, 偏移量为1567321。
4)修改从节点的同步信息
change master to master_host='10.16.130.79',master_user='replica', master_password='replica', master_port=3306, master_log_file='mysql-bin.000024', master_log_pos=偏移量为1567321, master_connect_retry=30;
5)开启主从同步
start slave;
4、再次进行数据同步, 问题终于重现
将表结构的ID重新去除, 只保留唯一索引, 进行新增数据的操作, 出现了上面的主从同步的问题, 到底是什么问题? 检查发现此项配置可疑:
slave-rows-search-algorithms='INDEX_SCAN,HASH_SCAN', 将此项配置注掉后, 重新进行主从同步验证, 问题消失。
1、
slave_rows_search_algorithms参数的作用
此参数是从节点接收到数据时, 采用何种方式进行数据查找, 取值如下:
上面出现问题的原因, 是在于没有启用TABLE_SCAN全表扫描,导致主从同步更新时, 报出HA_ERR_KEY_NOT_FOUND没有找到数据的错误, 但实际数据是存在,虽然有联合唯一索引, 但写入SQL的操作方式并不生效:
导致走HASH_SCAN方式。
2、HASH_SCAN方式存在缺陷
查阅相关资料, 发现主从同步走HASH_SCAN方式, 也出现过类似缺陷:
3、建议的解决方式
如何保障性能效率, 又能很好的解决此问题:
1) 不用修改主从同步参数
slave-rows-search-algorithms
仍采用“INDEX_SCAN,HASH_SCAN“方式, 这样是可以提升主从同步的效率
2)表结构必须加上主键(可以是自增ID也可以是联合主键), 从检索速度和稳定性来讲, 没特殊需要, 不建议采用字符类型作为主键。