发明内容
针对现有技术的以上缺陷或改进需求,本发明提供了一种基于日志解析同步的并行执行方法和数据同步系统,其目的在于,主要是通过冲突检测的机制,把本该在其它事务提交之后才能开始执行的操作提前执行,尽可能的把不冲突的事务操作提前执行,减少等待其它事务的提交次数,从而增加了并行度,在保证数据复制一致性的前提下,提高目的端数据复制的执行效率。
为实现上述目的,按照本发明的一个方面,提供了一种基于日志解析同步的并行执行方法,所述并行执行方法包括:
日志接收线程在获取到提交操作后,将所述提交操作所属的待执行事务分发至相对应的事务执行线程,其中,每一个事务执行线程负责一个待执行事务的入库处理;
从所述待执行事务中取出待执行操作,所述事务执行线程判断当前待执行操作的操作类型;
若当前待执行操作为DML操作,判断当前待执行操作与其他待执行事务是否存在冲突;
若存在,则将当前待执行操作所属的事务执行线程添加至冲突事务的唤醒链表中,在冲突解除后执行日志入库处理。
优选地,所述判断当前待执行操作与其他待执行事务是否存在冲突包括:
依次判断当前待执行操作的日志序列号是否均小于其他待执行事务的提交日志序列号;
若当前待执行操作的日志序列号大于本次检查的事务的提交日志序列号;
判断本次检查的事务是否已经完成整个事务的行锁构造;
若完成,则判断在本次检查的事务的行锁中,是否存在与当前待执行操作的行锁相同的目标行锁;
若存在,则将当前待执行操作所属的事务执行线程添加至本次检查的事务对应的提交唤醒链表中。
优选地,所述判断本次检查的事务是否已经完成整个事务的行锁构造包括:
若没有完成,则将当前待执行操作所属的事务执行线程添加至本次检查的事务的行锁唤醒链表中;
等待本次检查的事务完成整个事务的行锁构造后,执行所述判断在本次检查的事务的行锁中,是否存在与当前待执行操作的行锁相同的目标行锁的步骤。
优选地,所述判断在本次检查的事务的行锁中,是否存在与当前待执行操作的行锁相同的目标行锁之后还包括:
若不存在,则判断当前待执行操作的日志序列号是否小于下一个被检查的事务的提交日志序列号,直至完成全部事务的检查。
优选地,所述将当前待执行操作所属的事务执行线程添加至本次检查的事务对应的提交唤醒链表中之后还包括:
等待本次检查的事务完成提交后,将当前待执行操作添加至相应的待执行操作链表中;
从所述待执行事务中取出下一个待执行操作后,执行所述事务执行线程判断当前待执行操作的操作类型的步骤。
优选地,所述事务执行线程判断当前待执行操作的操作类型之后还包括:
若当前待执行操作为提交操作,本事务行锁已经构造完成,唤醒提交操作对应的行锁唤醒链表中的事务执行线程,让这些等待的事务进行行锁冲突检测;
执行并清空提交操作对应的待执行操作链表中的全部操作;
在待执行事务完成提交后,唤醒提交操作对应的提交唤醒链表中的事务执行线程,以解除提交冲突。
优选地,事务执行线程配套设置有一执行线程链表,所述执行线程链表用于登记事务执行线程中待执行事务的提交日志序列号;
所述执行并清空提交操作对应的待执行操作链表中的全部操作之后还包括:
获取提交操作的提交日志序列号LSN1,判断在执行线程链表中是否存在提交日志序列号小于LSN1的在先提交事务;
若存在,则将当前待执行操作所属的事务执行线程添加至所述在先提交事务对应的提交唤醒链表中;
在接收到所述在先提交事务的唤醒后,提交当前待执行操作所属的待执行事务。
优选地,所述若当前待执行操作为DML操作,判断当前待执行操作与其他待执行事务是否存在冲突包括:
若当前待执行操作为DML操作,根据当前待执行操作的ROWID信息构造当前待执行操作的行锁;
将当前待执行操作的行锁添加至相应的行锁哈希表中。
优选地,所述根据当前待执行操作的ROWID信息构造当前待执行操作的行锁之前还包括:
判断当前待执行操作的操作类型与待执行操作链表中已有的操作的操作类型是否相同;
若相同,则执行所述根据当前待执行操作的ROWID信息构造当前待执行操作的行锁的步骤;
若不相同,则执行并清空当前待执行操作对应的待执行操作链表中已有的操作后,执行所述根据当前待执行操作的ROWID信息构造当前待执行操作的行锁的步骤。
为实现上述目的,按照本发明的另一个方面,提供了一种数据同步系统,所述数据同步系统包括至少一个处理器;以及,与所述至少一个处理器通信连接的存储器;其中,所述存储器存储有可被所述至少一个处理器执行的指令,所述指令被程序设置为执行本发明所述的并行执行方法。
总体而言,通过本发明所构思的以上技术方案与现有技术相比,具有如下有益效果:本发明提供一种基于日志解析同步的并行执行方法和数据同步系统,所述并行执行方法包括:日志接收线程在获取到提交操作后,将所述提交操作所属的待执行事务分发至相对应的事务执行线程,其中,每一个事务执行线程负责一个待执行事务的入库处理;从所述待执行事务中取出待执行操作,所述事务执行线程判断当前待执行操作的操作类型;若当前待执行操作为DML操作,判断当前待执行操作与其他待执行事务是否存在冲突;若存在,则将当前待执行操作所属的事务执行线程添加至冲突事务的唤醒链表中,在冲突解除后执行日志入库处理。
在发明中,主要是通过冲突检测的机制,把本该在其它事务提交之后才能开始执行的操作提前执行,尽可能的把不冲突的事务操作提前执行,减少等待其它事务的提交次数,从而增加了并行度,在保证数据复制一致性的前提下,提高目的端数据复制的执行效率。
具体实施方式
为了使本发明的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本发明进行进一步详细说明。应当理解,此处所描述的具体实施例仅仅用以解释本发明,并不用于限定本发明。
在本发明的描述中,术语“内”、“外”、“纵向”、“横向”、“上”、“下”、“顶”、“底”等指示的方位或位置关系为基于附图所示的方位或位置关系,仅是为了便于描述本发明而不是要求本发明必须以特定的方位构造和操作,因此不应当理解为对本发明的限制。
此外,下面所描述的本发明各个实施方式中所涉及到的技术特征只要彼此之间未构成冲突就可以相互组合。
实施例1:
在数据同步中,在源端数据库及目的端数据库部署同步系统,源端数据同步系统从源端数据库读取日志,而目的端数据同步系统则是负责把源端发过来的同步操作应用到目的端数据库。
由于现有的数据同步的环境千差万别,为了最大限度的提升同步效率,需要根据当前数据同步环境的特性做针对性的优化,才能使得当前环境中的同步性能达到最优。本发明专门针对一种需要严格保证事务提交顺序的同步系统定制了同步优化方案,在这种系统中,目的端的事务在入库时,事务的提交顺序要求和源端事务的提交顺序完全保持一致,只有这样,目的端在任一时刻查询可见的数据的才能符合上层应用制定的数据关联逻辑,例如,业务系统中有关联的订单事务之间的先后顺序。为了达到这一目的,目的端数据同步系统在采用多线程并行入库源端事务时,线程之间执行的并行度取决于事务中各操作在日志中的先后顺序,并且对事务的提交也需要严格按照各事务提交操作中LSN的先后顺序来进行提交。由于数据库的提交操作相对来说是一个较慢的操作,制定出一套策略来减少线程之间对提交操作的等待可以有效的提升同步性能。
下面参阅图1,具体说明本实施例的基于日志解析同步的并行执行方法的过程,该并行执行方法包括如下步骤:
步骤101:日志接收线程在获取到提交操作后,将所述提交操作所属的待执行事务分发至相对应的事务执行线程,其中,每一个事务执行线程负责一个待执行事务的入库处理。
在本实施例中,目的端数据同步系统启动后需要初始化一个日志接收线程、一组事务执行线程和一条执行线程链表,其中,事务执行线程的具体数目依据实际情况而定,在此,不做具体限定。
其中,日志接收线程负责接收和管理从源端数据同步系统发过来的事务;事务执行线程则负责事务的执行入库;执行线程链表则是用来登记执行事务线程中待执行事务在源端的提交顺序,按照事务的提交日志序列号的大小进行顺序排列。
在本实施例中,日志接收线程在接收到源端的操作以后,对操作进行解析得到操作所属的事务ID(事务标识号),按照操作所属的事务ID进行分类,将各个操作归属至相应的事务中,当接收到提交操作后,将所述提交操作所属的待执行事务分发至相对应的事务执行线程。
具体地,在分发待执行事务到事务执行线程时,需要按事务的提交操作的日志序列号的大小顺序进行分发,提交日志序列号小的事务代表该事务在源端先提交,那么在目的端执行时,该事务就需要先被分发到事务执行线程,由此确保事务执行线程能够先开始执行在先提交的事务。
此外,事务执行线程在接收到分派的待执行事务时,提取该待执行事务的提交日志序列号,在执行线程链表中按照日志序列号的大小先后顺序进行登记。
步骤102:从所述待执行事务中取出待执行操作,所述事务执行线程判断当前待执行操作的操作类型。
在本实施例中,多个事务执行线程可以并行执行,每个事务执行线程从其所负责的待执行事务中取出一个待执行操作,判断当前待执行操作的类型,若当前待执行操作为DML(Data Manipulation Language,简写为DML)操作时,则执行步骤103。
步骤103:若当前待执行操作为DML操作,判断当前待执行操作与其他待执行事务是否存在冲突。
其中,冲突类型包括在先事务也对当前待执行操作所针对的对象进行DML操作,则需要等待在先事务在目的端提交之后,再对当前待执行操作进行处理,其中,在先事务指的是提交日志序列号小于当前待执行操作所属的事务的提交日志序列号的事务。
冲突类型还包括在先事务的行锁没有构造完成,则需要等待在先事务的行锁构造完成后,再对当前待执行操作进行处理。
步骤104:若存在,则将当前待执行操作所属的事务执行线程添加至冲突事务的唤醒链表中,在冲突解除后执行日志入库处理。
在本实施例中,若当前待执行操作与其他待执行事务不存在冲突,则当前待执行操作可以与其他待执行事务并行执行,若当前待执行操作与其他待执行事务存在冲突,则当前待执行操作可以与其他待执行事务串行执行,即,需要解除冲突后,再执行日志入库处理。
其中,每个事务执行线程启动后初始化一条行锁唤醒链表和一条提交唤醒链表,行锁唤醒链表则用来存放等待本事务操作的行锁构造完成以后需要唤醒的事务执行线程;提交唤醒链表则用来存放等待本事务提交完成以后需要唤醒的事务执行线程。
结合图4,若当前待执行操作为提交操作,且本事务行锁已经构造完成,其中,本事务指的是所述当前待执行操作所属的事务,则唤醒行锁唤醒链表中的事务执行线程,让这些等待的事务进行行锁冲突检测,其中,前述这些等待的事务指的是行锁唤醒链表中的事务执行线程所负责的事务。然后,执行清空待执行操作链表中的操作并提交,完成提交后,唤醒提交唤醒链表中的事务执行线程。
在本实施例中,主要是通过冲突检测的机制,把本该在其它事务提交之后才能开始执行的操作提前执行,尽可能的把不冲突的事务操作提前执行,减少等待其它事务的提交次数,从而增加了并行度,在保证数据复制一致性的前提下,提高目的端数据复制的执行效率。在实际应用场景下,在步骤103之前,还需要对当前待执行操作构造行锁,每一事务执行线程还配套设置有行锁哈希表和待执行操作链表,所述行锁哈希表用于存放操作的行锁信息,所述待执行操作链表用于缓存待执行操作。
在本实施例中,若当前待执行操作为DML操作,根据当前待执行操作的ROWID信息构造当前待执行操作的行锁,将当前待执行操作的行锁添加至相应的行锁哈希表中。在进行冲突检测时,根据当前待执行操作的基于ROWID信息构成的行锁,判断当前待执行操作与在先事务是否存在行锁冲突,若在先事务中存在相同的行锁,则当前待执行操作与在先事务存在行锁冲突。
为了提高同步的效率,对于相同的操作可以批量执行,因此,在优选的实施例中,在构造行锁信息之前,判断当前待执行操作的操作类型与待执行操作链表中已有的操作的操作类型是否相同;若当前待执行操作的操作类型与待执行操作链表中已有的操作的操作类型相同,根据当前待执行操作的ROWID信息构造当前待执行操作的行锁,将当前待执行操作的行锁添加至相应的行锁哈希表中,然后对当前待执行操作进行冲突检测。
若当前待执行操作的操作类型与待执行操作链表中已有的操作的操作类型不相同,则执行并清空当前待执行操作对应的待执行操作链表中已有的操作,在进行入库时,批量执行待执行操作链表中已有的操作。在待执行操作链表清空后,对当前待执行操作进行冲突检测。
其中,ROWID用于定位数据库中一条记录的一个相对唯一地址值,通常情况下,该值在该行数据插入到数据库表时即被确定且唯一,ROWID是根据每一行数据的物理地址信息编码而成的一个伪列,所以根据一行数据的ROWID能找到一行数据的物理地址信息,从而快速地定位到数据行。
在本实施例中,主要是通过ROWID检测冲突的方式,把本该在其它事务提交之后才能开始执行的操作提前执行,尽可能的把不冲突的事务操作提前执行,减少等待其它事务的提交次数,从而增加了并行度。行锁唤醒链表结合执行线程链表确保ROWID行锁构造的先后顺序,提交唤醒链表结合执行线程链表来确保冲突的事务执行顺序,执行线程链表则用来确保事务的提交顺序。
结合图2和图4,其中,图4仅简略说明每一步骤,不过图4基本展示了并行执行方法的整个流程支路,主要便于理解本方案,具体说明步骤103中冲突检测的具体实现过程,其中,步骤103具体包括如下步骤:
步骤1031:依次判断当前待执行操作的日志序列号是否均小于其他待执行事务的提交日志序列号。
在本实施例中,事务执行线程配套设置有一执行线程链表,所述执行线程链表用于登记事务执行线程中待执行事务的提交日志序列号,其中,以提交日志序列号从小到大的顺序进行登记。
按照从后往前的顺序,从所述执行线程链表取出待执行事务的提交日志序列号,为便于下文描述,将本次取出的待执行事务记作本次检查的事务。首先,判断当前待执行操作的日志序列号是否小于本次检查的事务的提交日志序列号,若小于,则继续取出下一个检查的事务,比较日志序列号的大小,直至完成对执行线程链表中的所有事务的日志序列号的比较。
若当前待执行操作的日志序列号均小于其他待执行事务的提交日志序列号,则当前待执行操作与其他事务无冲突,则将当前待执行操作添加至待执行操作链表,然后从待执行事务中取出下一个操作。
将当前待执行操作添加到待执行操作链表后,判断待执行操作链表中已有的操作的数目是否已经达到设定值,若达到设定值,则将待执行操作链表中已有的操作批量入库,以清空待执行操作链表,防止待执行操作链表缓存太多的操作,从而影响到内存的占用。
在本实施例中,采用链表缓存的方式先缓存相同的操作,积累到一定数量以后再批量执行入库可以减少和数据库交互的次数,从而提升执行性能。
若当前待执行操作的日志序列号大于本次检查的事务的提交日志序列号,则执行步骤1032。
在本实施例中,当前待执行操作的日志序列号如果比在先事务的提交日志序列号小,说明该操作在源数据库中是和该事务是共存的,所以目的端执行的时候可以和该事务中的所有操作并行执行,从而省去了检查ROWID冲突的步骤。当前待执行操作的日志序列号如果比在先事务的提交日志序列号大,则需要进行ROWID冲突检测,而且,如果在先提交的事务还没有完成行锁的构造,那就需要等待该事务构造完行锁以后才能进行冲突检查,具体过程如下。
步骤1032:若当前待执行操作的日志序列号大于本次检查的事务的提交日志序列号,判断本次检查的事务是否已经完成整个事务的行锁构造。
若本次检查的事务已经完成整个事务的行锁构造,则执行步骤1033,若本次检查的事务没有完成整个事务的行锁构造,则执行步骤1034。
步骤1033:若完成,则判断在本次检查的事务的行锁中,是否存在与当前待执行操作的行锁相同的目标行锁。
由于各个操作的行锁是基于ROWID信息进行构造的,而ROWID信息可以定位数据库中一条记录的一个相对唯一地址值,因此,可以根据基于ROWID信息构造的行锁判断是否存在行锁冲突。
若存在行锁冲突,则执行步骤1035,若不存在行锁冲突,判断当前待执行操作的日志序列号是否小于下一个被检查的事务的提交日志序列号,直至完成全部事务的检查。
步骤1034:若没有完成,则将当前待执行操作所属的事务执行线程添加至本次检查的事务的行锁唤醒链表中。
在本实施例中,等待本次检查的事务完成整个事务的行锁构造后,再返回至步骤1032,判断在本次检查的事务的行锁中,是否存在与当前待执行操作的行锁相同的目标行锁。
在实际应用场景下,对于规模比较大的事务(例如,大于100M的事务),如果事先完成行锁的构造,一方面浪费时间,另一方面会占用较大的内存,而在本实施例中,可以在检测冲突的同时构造行锁,不仅提高效率,还节省了内存。
步骤1035:若存在,则将当前待执行操作所属的事务执行线程添加至本次检查的事务对应的提交唤醒链表中。
在本实施例中,若存在行锁冲突,则将当前待执行操作所属的事务执行线程添加至本次检查的事务对应的提交唤醒链表中,等待本次检查的事务完成提交后,将当前待执行操作添加至相应的待执行操作链表中。
将当前待执行操作添加至待执行操作链表中后,从所述待执行事务中取出下一个待执行操作后,返回步骤102,所述事务执行线程判断当前待执行操作的操作类型。
前述主要针对DML操作的冲突检测进行说明,在当前待执行操作为提交操作时,一方面用于待同步事务的入库处理,另一方面用于解除冲突,具体的实现过程如下,结合图3和图4,在本实施例中,并行执行方法包括如下步骤:
步骤101:日志接收线程在获取到提交操作后,将所述提交操作所属的待执行事务分发至相对应的事务执行线程,其中,每一个事务执行线程负责一个待执行事务的入库处理。
步骤102:从所述待执行事务中取出待执行操作,所述事务执行线程判断当前待执行操作的操作类型。
在本实施例中,若当前待执行操作为DML操作,则执行步骤103;若当前待执行操作为提交操作,则执行步骤105。
步骤103:若当前待执行操作为DML操作,判断当前待执行操作与其他待执行事务是否存在冲突。
步骤104:若存在,则将当前待执行操作所属的事务执行线程添加至冲突事务的唤醒链表中,在冲突解除后执行日志入库处理。
其中,步骤101~步骤104可以详见前述描述,在此不在赘述。
步骤105:若当前待执行操作为提交操作,本事务行锁已经构造完成,唤醒提交操作对应的行锁唤醒链表中的事务执行线程,让这些等待的事务进行行锁冲突检测。
在本实施例中,若当前待执行操作为提交操作,且本事务行锁已经构造完成,唤醒提交操作对应的行锁唤醒链表中的事务执行线程,激活那些等待本事务构造完事务行锁的事务执行线程重新进行冲突检测,以判断是否存在行锁冲突。
前述结合步骤1034,行锁唤醒链表中的事务执行线程被唤醒后,将当前待执行操作添加至相应的待执行操作链表中。
步骤106:执行并清空提交操作对应的待执行操作链表中的全部操作。
在本实施例中,唤醒提交操作对应的行锁唤醒链表中的事务执行线程,执行并清空提交操作对应的待执行操作链表中的全部操作。
步骤107:获取提交操作的提交日志序列号LSN1,判断在执行线程链表中是否存在提交日志序列号小于LSN1的在先提交事务。
在本实施例中,先将事务进行入库,先不提交,在进行事务提交之前,还需确认是否有在先事务没有提交,若有在先事务没有提交,则需要等待在先事务提交后,再进行本事务的提交。
具体地,获取提交操作的提交日志序列号LSN1,判断在执行线程链表中是否存在提交日志序列号小于LSN1的在先提交事务。
其中,事务提交后,会删除在执行线程链表中登记的日志序列号,因此,可以通过执行线程链表确定是否存在还未提交的在先事务。
步骤108:若存在,则将当前待执行操作所属的事务执行线程添加至所述在先提交事务对应的提交唤醒链表中。
在本实施例中,若存在,则存在提交冲突,将当前待执行操作所属的事务执行线程添加至所述在先提交事务对应的提交唤醒链表中。
步骤109:在接收到所述在先提交事务的唤醒后,提交当前待执行操作所属的待执行事务。
步骤110:在待执行事务完成提交后,唤醒提交操作对应的提交唤醒链表中的事务执行线程,以解除提交冲突。
前述结合步骤1035,提交唤醒链表中的事务执行线程被唤醒后,将当前待执行操作添加至相应的待执行操作链表中。
在本实施例中,ROWID是数据库组织数据的方式,虽然不同的数据库在ROWID的结构上有不同的体现形式,有的采用物理地址构成,例如ORACKE,有的采用逻辑整数,例如DM7等,但是都遵循一个原则,就是在单个表上每行数据的ROWID值都是唯一的。在数据库记录的日志操作中,每个操作的日志上都带有相应的ROWID信息,用来标记日志操作对应的数据行。数据库的运行机制保证相同ROWID的数据不允许被多个事务并行的修改,那么数据同步在把这些带有ROWID信息的操作入库时,就可以通过互斥包含相同ROWID信息的事务,把相冲突的事务串行执行,而无冲突的事务操作并行执行增加并行度,再串行提交确保数据逻辑的一致性。
在本实施例中,在将当前待执行操作添加在待执行操作链表之前,还需要判断当前待执行操作与待执行操作链表中的操作是否可以合并执行,若可以合并执行,则将当前待执行操作添加在待执行操作链表中;若不可以合并执行,则清空待执行操作链表中已有的操作后,再将当前待执行操作添加在待执行操作链表中。
下面,简要说明判断当前待执行操作与待执行操作链表中的操作是否可以合并执行的实现过程:
在本实施例中,日志接收线程在接收到提交操作后,按照顺序为所述提交操作设置提交编号,日志接收线程在接收到DML操作后,获取发生于所述DML操作之前,且最接近于所述DML操作的提交操作的目标提交编号,采用所述目标提交编号标记所述DML操作。
在完成前述实施例中的冲突检测后,根据所述当前待执行操作所携带的目标提交编号,确定所述当前待执行操作与其他待执行事务的相容性,进而确定是否可以进行操作合并。
具体地,在其他待执行事务中,根据所述当前待执行操作所携带的目标提交编号确定与所述当前待执行操作存在冲突的冲突事务,其中,所述冲突事务指的是在日志流中,本事务的两个相邻操作之间还夹杂着提交操作,该提交操作所属的待执行事务为冲突事务。在确定了冲突事务后,判断冲突事务中是否存在与所述当前待执行操作相关联的关联对象,若不存在,则所述当前待执行操作与所述冲突事务相容;若存在,则进一步判断冲突事务对关联对象所进行的操作与所述当前待执行操作是否相容,若相容,则将所述当前待执行操作添加至待执行操作链表的尾端;若不相容,则等待冲突事务提交后,再将所述当前待执行操作添加至待执行操作链表的尾端。
在本实施例中,数据库日志记录中的LSN代表着日志对应的操作在数据库中执行的顺序,通过对比日志操作LSN和事务提交消息的LSN可以清楚的推断出日志操作在源数据库中和其它事务的共存状态,目的端数据同步系统根据事务共存状态就可以制定出一套并行执行策略,然后根据事务LSN的先后顺序来串行提交,这样再结合ROWID冲突检测策略,即可以有效的增加事务入库的并行度,又可以保证事务提交的顺序和源端数据库保持一致,从而提升同步的性能。
实施例2:
源数据库和目的端数据库都存在表T(ID INT PRIMARY KEY,C1 INT),其中,源端应用有两个事务(TRX1和TRX2)对表T并行操作,TRX1对T表插入10行数据,ID为1到10;TRX2对T表插入2行数据,ID为20和21,然后更新一行数据,更新的ID为1,产生如下日志:
在目的端同步系统初始化了两个事务执行线程,分别为EXEC1和EXEC2,上述日志执行过程如下:
日志接收线程接收到上述两个事务后,按事务提交顺序把TRX1和TRX2分派给两个执行线程,将事务TRX1分配给事务执行线程EXEC1,将事务TRX2分配给事务执行线程EXEC2,下面具体说明这两个事务执行线程并行执行过程。
针对事务执行线程EXEC1:首先,提取ID为1的INSERT操作,判断当前操作的操作类型和待执行操作链表中的操作类型是否一致,不一致,则需要执行待执行操作链表中已经缓存的操作并清空该链表,由于待执行操作链表为空链表,无需执行。然后,提取ROWID构造行锁并进行冲突检测,TRX1是线程链表中排一的事务,所以无冲突,把ID为1的INSERT操作添加到待执行操作链表。
针对事务执行线程EXEC1:提取ID为2的INSERT操作,判断当前操作和待执行链表中的操作是否一致,不一致则需要执行待执行链表中缓存的操作并清空该链表,由于待执行操作链表中的操作是INSRT操作,一致,无需清空链表。提取ROWID构造行锁并进行冲突检测,TRX1是管理线程链表中排第一的事务,所以无冲突,把ID为2的INSERT操作添加到待执行操作链表。ID从2到10的INSERT操作运行逻辑和ID为1的逻辑一致,在此省略。
针对事务执行线程EXEC2:提取ID为20的INSERT操作,判断当前操作和待执行链表中的操作是否一致,不一致则需要执行执行链表中缓存的操作并清空该链表,由于当前链表为空链表,无需执行。提取ROWID构造行锁并进行冲突检测,TRX2是管理线程链表中排二的事务,所以它需要和排在它前面的TRX1进行冲突检测,按照检查规则,由于该操作的LSN值为2,比TRX1的提交LSN值12要小,所以该操作和TRX1在源库中是并存的,可以并行执行,无冲突,把该操作添加到待执行操作链表。
针对事务执行线程EXEC2:提取ID为21的INSERT操作,判断当前操作和待执行操作链表中的操作是否一致,不一致则需要执行待执行操作链表中缓存的操作并清空该链表,由于当前链表中的操作是INSRT操作,一致,无需清空链表。提取ROWID构造行锁并进行冲突检测,TRX2是管理线程链表中排二的事务,所以它需要和排在它前面的TRX1进行冲突检测,按照检查规则,由于该操作的LSN值为13,比TRX1的提交LSN值12要大,所以还需要通过ROWID来进行冲突检测,但这个时间点上TRX1还未完成事务行锁的构造,所以执行线程EXEC2添加到EXEC1的行锁唤醒链表,等待事务TRX1完成行锁构造以后再唤醒自己。
针对事务执行线程EXEC1:提取到COMMIT操作,唤醒行锁唤醒链表中的EXEC2,清空并执行待执行操作链表中的操作,把缓存的操作入库。进行提交顺序检测,TRX1是管理线程链表中排一的事务,所以无冲突,执行提交,唤醒提交唤醒链表中的EXEC2。
针对事务执行线程EXEC2:在接收到唤醒消息后,再次用ROWID进行冲突检测,此时在TRX1中并未找到ID为21的ROWID锁,无冲突,把该操作添加到待执行操作链表,提取ID为1的UPDATE操作,判断当前操作和待执行链表中的操作是否一致,由于待执行链表中现存的是INSERT操作,不一致,需要先把待执行链表中的操作入库,批量执行:INSERT INTO T(ID,C1)VALUES(20,20),(21,21)。
针对事务执行线程EXEC2:提取ROWID构造行锁并进行冲突检测,TRX2是管理线程链表中排二的事务,所以它需要和排在它前面的TRX1进行冲突检测,按照检查规则,由于该操作的LSN值为14,比TRX1的提交LSN值12要大,所以要再进行ROWID冲突检查,发现ID为1的ROWID在TRX1中存在行锁,存在冲突,需要等待TRX1提交完成以后才能执行,所以执行线程EXEC2添加到EXEC1的提交唤醒链表,等待事务TRX1完成提交以后再唤醒自己,把UPDATE操作添加到待执行操作链表。
针对事务执行线程EXEC2:在接收到唤醒消息后,提取到提交消息,按照EXEC1的方式执行并清空待执行链表以后完成提交。
在本具体应用场景下,负责TRX1事务入库的执行线程EXEC1由于排在线程链表的第一个,说明它是最先提交的事务,那么它执行的时候就不受其它事务的约束,可以畅通无阻的执行,而负责TRX2事务入库的执行线程EXEC2,由于它在执行线程链表前面还有EXEC1,那么它在入库TRX2事务时,就会受到TRX1事务入库进度的约束。
从上面执行线程EXEC2的执行流程中可以看到,第一个INSERT(ID=20)操作由于它的LSN比TRX1的提交LSN小,所以它可以和TRX1共存,而第二个INSERT(ID=21)操作则需要通过ROWID检测的方式才能确认它和TRX1中的操作是否存在冲突,由于TRX1操作数量较多,EXEC2需要等待EXEC1完成TRX1事务所有操作的ROWID收集以后才能进行ROWID冲突检测,通过添加到EXEC1行锁唤醒链表来实现这种等待。当EXEC1在碰到提交操作时,先唤醒EXEC2,然后再继续执行,这样可以提升两个线程的并行度。EXEC2唤醒后,由于第二个INSERT操作和TRX1中的ROWID并没有冲突,所以,待执行操作链表中的两个INSERT操作就可以进行入库操作,第二个INSERT(ID=21)操作从源端日志流中看,它排在了TRX1提交操作之后,在源数据库上,该操作是要在TRX1提交完成以后才执行,通过使用本实施例的并行策略,把它提前到TRX1提交之前来执行,从而增加了并行度。TRX2第三个UPDATE操作,由于它更新的行是TRX1插入的行,必须要等到TRX1提交以后才能执行,所以通过EXEC2添加到EXEC1的提交唤醒链表来实现等待功能,从而满足数据上的先后逻辑。
实施例4:
请参阅图5,图5是本发明实施例提供的一种数据同步系统的结构示意图。本实施例的数据同步系统包括一个或多个处理器41以及存储器42。其中,图5中以一个处理器41为例。
处理器41和存储器42可以通过总线或者其他方式连接,图5中以通过总线连接为例。
存储器42作为一种基于并行执行方法的非易失性计算机可读存储介质,可用于存储非易失性软件程序、非易失性计算机可执行程序以及模块,上述实施例的方法以及对应的程序指令。处理器41通过运行存储在存储器42中的非易失性软件程序、指令以及模块,从而执行各种功能应用以及数据处理,实现前述实施例的方法。
其中,存储器42可以包括高速随机存取存储器,还可以包括非易失性存储器,例如至少一个磁盘存储器件、闪存器件、或其他非易失性固态存储器件。在一些实施例中,存储器42可选包括相对于处理器41远程设置的存储器,这些远程存储器可以通过网络连接至处理器41。上述网络的实例包括但不限于互联网、企业内部网、局域网、移动通信网及其组合。
值得说明的是,上述装置和系统内的模块、单元之间的信息交互、执行过程等内容,由于与本发明的处理方法实施例基于同一构思,具体内容可参见本发明方法实施例中的叙述,此处不再赘述。
本领域普通技术人员可以理解实施例的各种方法中的全部或部分步骤是可以通过程序来指令相关的硬件来完成,该程序可以存储于一计算机可读存储介质中,存储介质可以包括:只读存储器(Read Only Memory,简写为ROM)、随机存取存储器(RandomAccessMemory,简写为RAM)、磁盘或光盘等。
本领域的技术人员容易理解,以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内所作的任何修改、等同替换和改进等,均应包含在本发明的保护范围之内。