mysql可以支持多种不同的存储引擎,innodb由于其高效的读写性能,并且支持事务特性,使得它成为mysql存储引擎的代名词,使用非常广泛。随着SSD逐渐普及,硬件存储成本越来越高,面向写优化的rocksdb引擎逐渐流行起来,我们也是看中了rocksdb引擎在写放大和空间放大的优势,将其引入到mysql体系。两种引擎的结构B-Tree(innodb引擎)和LSM-Tree(rocksdb引擎)很好地形成互补,我们可以根据业务类型来选择合适的存储。一般mysql默认是mysql+innodb引擎,而mysql+rocksdb引擎称之为myrocks。今天要讨论的就是myrocks复制中断问题,案例来源于真实的业务场景。
问题现象
复制过程中,出现了1756错误,根据错误日志和debug确认是slave-sql线程在更新slave_worker_info表时出错导致,堆栈如下:
这里简单介绍下复制相关的位点表,在并行复制模式下,参与复制的主要有三个角色,slave_io线程负责将主库的binlog拉取到本地;slave_sql线程读取binlog并根据一定的规则分发给各个slave_worker;slave_worker线程回放主库的操作,达到与主库同步的目的。slave_io线程和slave_sql线程分别只有一个,而worker线程可以有1个或多个,可以依据参数slave_parallel_workers设置。如果将slave_parallel_workers设置为0,则表示关闭并行复制,slave_sql线程承担回放的工作。位点表主要有3张,包括slave_worker_info,slave_relay_log_info和slave_master_info表。slave_io线程更新slave_master_info表,更新拉取的最新位置;slave_sql线程更新slave_relay_log_info表,更新同步位点;而slave_worker线程更新slave_worker_info,每个worker线程在该表中都对应一条记录,每个worker各自更新自己的位点。
Slave_worker的工作流程如下:
1) 读取event,调用do_apply_event进行回放;
2) 遇到xid event(commit/rollback event),表示事务结束,调用commit_positions更新位点信息;
3) 调用do_commit提交事务。
从我们抓的堆栈来看,是worker线程在执行执行第2步出错,现在我们得到了初步的信息,更新位点表失败直接导致了错误。
问题定位与分析
接下来,我们将了解最终导致位表更新失败的原因。根据最终的错误代码,我们在调试过程中设置了几个断点,最终得到如下堆栈
[En]
Next, we'll see what ultimately caused the failure to update the bit table. According to the final error code, we set several breakpoints during debugging and finally get the following stack