共计 1056 个字符,预计需要花费 3 分钟才能阅读完成。
一、背景
当备库回放事务时,多个相互不依赖的事务能够并发回放,本办法次要用于解决多个可并发回放的事务的并发回放问题。通过并发的多个扫描线程实现并发对事物回放队列进行扫描,生成多个能够并发回放的事物,并且告诉回放线程进行并发的回放。
二、数据结构设计
备库的事物数据依照事物 ID 分段存储到备库的事物数据队列中,参考如下图 1;依据事物 ID 为 UUID 齐全无序的个性,能够对 UUID 进行事物 ID 分段并发扫描。将事物 ID UUID 分段后,交给多个扫描线程协程,每个扫描线程负责某个 UUID 分区进行多个扫描线程并发扫描,扫描可回放的事物。
三、线程生命周期
当扫描线程发现可回放的事物后,会将事物 ID 退出 txnList 执行 enqueu 操作,退出事物 ID 后,扫描线程会执行 notify 操作,唤醒正在睡眠的回放线程进行事务回放操作,示意图参考如下图 2。
回放线程协程的生命周期如下如图 3,回放线程刚启动后处于睡眠状态,当有事务回放时,会被随机唤醒。被唤醒的回放线程协程会执行事务回放工作,并且清理事务的依赖关系。
当发现可回放的事务时,如果发现可回放的事务数等于 1,则由以后协程进行回放缩小一次 CPU 切换的开销;当发现多余 1 个可回放事务时,回放线程协程会将除去第一个的可回放事务,退出 txnList 唤醒其余协程进行事务回放,以实现更好回放的并发性能。
四、并发切换问题
在采取了并发清理时,因为 CPU 切换的问题,须要解决反复发现的可回放事务,对反复发现雷同的事务 ID 进行防御性幂等解决,如下图 4。因而,须要对每个可回放事务引入 txnIDSet 进行幂等解决。
五、如何判断回放是否完结
因为采取了并发扫描以及并发回放,所以须要在全副可回放事务全副回放完结后,完结回放的流程,在此给出回放完结的定义。
当可回放事务全副回放完结后,认为回放完结。可回放事务分为 3 类,过来发现的可回放事务 / 当初发现的可回放事务 / 未来发现的可回放事务。
过来发现的可回放事务都会被退出到 txnList 中,当初发现的可回放事务正在由回放线程进行回放,未来发现的可回放事务是由扫描线程扫描 UUID 进行发现的。
- 过来发现的事务回放完结的条件为 txnList 为空;
- 当初发现的事务回放完结的条件为所有的 workerStatus 总和为 0;
- 未来发现的事务回放完结的条件为所有的扫描线程,GatherAll 扫描可回放事务无奈发现。
六、性能调优
依据 CPU 数量,可通过动静调整扫描线程和回放线程的回放协程数量,以正当调配两组协程的负载。这样做能够充分利用多核处理器的性能,并进步零碎的吞吐量和响应能力。