一种基于日志解析同步的日志读取方法和数据同步***
技术领域
本发明属于数据同步技术领域,更具体地,涉及一种基于日志解析同步的日志读取方法和数据同步***。
背景技术
在基于日志解析同步的方案中,源端数据库上会布署一个数据库日志抓取进程,对数据库的在线日志不断的扫描读取,以便第一时间抓取数据库的运行日志进行数据同步。这种架构会造成数据库的日志文件被两个或多个进程同时打开,其中,数据库打开在线日志文件并写入日志,而数据同步进程则打开在线日志文件读取日志,如果数据库的写和数据同步的读操作同时并发在同一个在线日志文件的同一个文件偏移上,就可能会造成读写冲突,导致数据库即将写入的新数据被数据同步从日志文件中读取的旧数据冲掉。这主要是由于操作***或是硬件设备在某些环境下针对同一个文件同一个偏移使用同一片缓存来进行读写访问导致,数据库写入的日志先写入该缓存,还没有完成刷盘之前,数据同步线程的读操作把日志文件中相同位置的旧数据读取到了该缓存中,从而覆盖了数据库写入的新数据,最终刷盘实际写入的还是日志文件中的旧数据。经过测试,这种现像在虚拟机的运行环境下发生机率很高,一旦发生,会导致数据同步出错,更严重的是,如果在这时数据库故障重启,数据库将无法利用这种被破坏的REDO日志进行恢复。所以如何解决数据库进程和数据同步进程同时访问在线日志文件的读写冲突就成为业界亟待解决的技术问题。
鉴于此,克服该现有技术产品所存在的不足是本技术领域亟待解决的问题。
发明内容
针对现有技术的以上缺陷或改进需求,本发明提供了一种基于日志解析同步的日志读取方法和数据同步***,其目的在于,通过定时轮询的方式获取日志序列号和日志时间的映射关系,从而计算待同步日志记录和当前数据库最新的日志之间的时间差,让这个时间差永远保持在一个设定值范围之外就可以有效的防止数据同步进程和数据库日志写入进程对日志文件的读写访问产生冲突。
为实现上述目的,按照本发明的一个方面,提供了一种基于日志解析同步的日志读取方法,所述日志读取方法包括:
在一个轮询区间内,获取源端数据库当前最大的日志序列号和当前时间;
将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表;
从日志文件中读取待同步日志记录,获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间;
根据所述待同步日志记录所属的写入时间和当前***时间之间的差值大小,进行策略性日志读取和同步。
优选地,所述根据所述待同步日志记录所属的写入时间和当前***时间之间的差值大小,进行策略性日志读取包括:
判断所述待同步日志记录所属的写入时间和当前***时间之间的差值是否大于最小延时时间;
若大于,将所述待同步日志记录同步至目的端,并从日志文件中获取下一个待同步日志记录后,执行所述获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间,以进行策略性日志读取和同步。
优选地,所述根据所述待同步日志记录所属的写入时间和当前***时间之间的差值大小,进行策略性日志读取还包括:
若不大于,则暂停日志读取,并以轮询的方式计算所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值;
当所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值不小于最小延时时间时,从日志文件中获取下一个待同步日志记录后,执行所述获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间,以进行策略性日志读取和同步。
优选地,所述以轮询的方式计算所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值包括:
按照设定的时间间隔从所述日志文件中取出当前读取日志记录;
获取所述当前读取日志记录的日志序列号,以从所述LSN信息链表中获取所述当前读取日志记录所属的写入时间;
计算所述当前读取日志记录的写入时间与当前***时间之间的差值。
优选地,所述从日志文件中读取待同步日志记录,获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间;
从日志文件中读取待同步日志记录,获取所述待同步日志记录的日志序列号LSN0;
从所述LSN信息链表中查找最接近于所述日志序列号LSN0,且大于所述日志序列号LSN0的目标日志序列号;
获取所述目标日志序列号对应的时间;
将所述目标日志序列号对应的时间设置为所述待同步日志记录所属的写入时间。
优选地,所述将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表之前还包括:
判断所述当前最大的日志序列号与前一次获取到的日志序列号是否相等;
若相等,则通过更新辅助表的方式推进日志;
若不相等,则执行所述将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表的步骤。
优选地,所述通过更新辅助表的方式推进日志包括:
建立所述辅助表,并在所述辅助表中初始化一行目标数据;
更新所述目标数据,以推进所述源端数据库日志。
优选地,所述从日志文件中读取待同步日志记录包括:
从所述日志文件中读取日志记录,获取所述日志记录所针对的对象;
当所述日志记录所针对的对象是所述辅助表时,直接过滤所述日志记录;
当所述日志记录所针对的对象不是所述辅助表时,将所述日志记录标记为待同步日志记录。
优选地,所述LSN信息链表中包含指定个数的日志记录的日志序列号和日志序列号所属的时间;其中,所述指定个数依据最小同步延迟时间而定。
为实现上述目的,按照本发明的另一个方面,提供了一种数据同步***,所述数据同步***包括至少一个处理器;以及,与所述至少一个处理器通信连接的存储器;其中,所述存储器存储有可被所述至少一个处理器执行的指令,所述指令被程序设置为执行本发明所述的部分回滚解析方法。
总体而言,通过本发明所构思的以上技术方案与现有技术相比,具有如下有益效果:一种基于日志解析同步的日志读取方法和数据同步***,所述日志读取方法包括:在一个轮询区间内,获取源端数据库当前最大的日志序列号和当前时间;将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表;从日志文件中读取待同步日志记录,获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间;根据所述待同步日志记录所属的写入时间和当前***时间之间的差值大小,进行策略性日志读取和同步。
在本发明中,为了避免数据同步进程和数据库日志写入进程的日志读写冲突,必须防止这两个进程在同一时刻同时访问同一个文件中相同偏移的数据。为了达到这个目的,数据同步***通过在数据库中定时查询数据库的日志序列号,然后把获取的日志序列号和当前时间进行关联后,添加在LSN信息链表中,数据同步***在读取日志文件时,需要拿当前待同步日志记录中的日志序列号和LSN信息链表中的值进行对比,定位到该日志记录对应的写入时间,从而计算待同步日志记录和当前***时间的时间差,让这个时间差永远保持在一个设定值范围之外就可以有效的防止数据同步进程和数据库日志写入进程对日志文件的读写访问产生冲突。
附图说明
图1是本发明实施例提供的一种基于日志解析同步的日志读取方法的流程示意图;
图2是本发明实施例提供的另一种基于日志解析同步的日志读取方法的流程示意图;
图3是本发明实施例提供的一种数据同步***的结构示意图;
图4是本发明实施例提供的另一种数据同步***的结构示意图。
具体实施方式
为了使本发明的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本发明进行进一步详细说明。应当理解,此处所描述的具体实施例仅仅用以解释本发明,并不用于限定本发明。
在本发明的描述中,术语“内”、“外”、“纵向”、“横向”、“上”、“下”、“顶”、“底”等指示的方位或位置关系为基于附图所示的方位或位置关系,仅是为了便于描述本发明而不是要求本发明必须以特定的方位构造和操作,因此不应当理解为对本发明的限制。
此外,下面所描述的本发明各个实施方式中所涉及到的技术特征只要彼此之间未构成冲突就可以相互组合。
实施例1:
目前,虽然数据锁技术可以只允许一个进程访问某一文件,但是数据锁适用于同一种数据库或者同一种厂家的数据库,如果写入数据库和读取数据库是来自不同的厂家,即源端数据库这一侧的写操作和目的端数据库这一侧的读操作源自不同两个厂家的数据库,所以,无法采用上面的数据锁,本实施例的方法适用于不同来源或者不同类型的数据库。
结合图3,在本实施例中,在源端数据库及目的端数据库部署同步***,源端数据库同步***从源端数据库读取日志,而目标端数据库同步***则是负责把源端发过来的同步操作应到目的端数据库。
其中,源端数据同步***在启动时,需要初始化一条LSN信息链表、一个数据库交互线程和一个日志文件读取线程。数据库交互线程用于定时从源端数据库获取日志记录的最大日志序列号和源端数据库当前时间来维护LSN信息链表;日志文件读取线程用于读取数据库的日志文件进行解析。在本实施例中,所述数据库交互线程、所述日志文件读取线程和LSN信息链表共同作用,避免数据同步进程和数据库日志写入进程的日志读写冲突。
下面参阅图1具体说明本实施例的基于日志解析同步的日志读取方法的具体实现过程,所述日志读取方法包括如下步骤:
步骤101:在一个轮询区间内,获取源端数据库当前最大的日志记录的日志序列号和当前时间。
在实际应用场景下,数据库产生的每条日志记录中都LSN值,它代表该日志产生的顺序。而LSN的表现形式在不同数据库上各不相同,有物理LSN,它采用类似日志文件的编号+日志页号+日志页内偏移来构成,例如Postgresql,Sql server和DM6等;有逻辑LSN,它采用一个顺序递增的整数来构成,例如,ORACLE和DM7等。不管是哪种形式,它们都遵循一个原则,就是日志序列号LSN随着数据库的运行严格的递增。
其次,虽然某些数据库日志的日志序列号LSN可以通过数据库转换得到相应的日志发生时间(例如,ORACLE),但这不是一个通用的功能,所以数据同步通过定时轮询的方式获取日志序列号LSN和日志时间的映射关系,可以有效的适配大多数数据库采用基于日志解析同步的日志读取方案。
其中,轮询区间具体依据实际情况而定,例如,轮询区间为1s,在一个轮询区间内可能会产生多条日志,在本实施例中,获取在该轮询区间内的最新的日志记录的日志序列号,即当前最大的日志序列号,以及当前时间,从而将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表。
步骤102:将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表。
在本实施例中,源端数据同步***初始化一个LSN信息链表,用于存储日志序列号与日志序列号相关的时间信息。其中,所述LSN信息链表中包括指定个数的日志记录的日志序列号和日志记录所属的时间。其中,指定个数可以依据最小同步延时时间而定,可以防止LSN信息链表无限的膨胀。
举例而言,假如设定最小的同步延时为5秒,那么LSN信息链表中只用存放差不多最近的5秒钟轮询到的LSN和时间映射关系,在读取日志以后,取出日志的LSN,在LSN信息链表中定位时间时,如果LSN小于信息链表中第一个LSN,那么它的映射时间就可以设置为第一个LSN所属的时间,则该日志发生于5秒之前,虽然,可能它的真实映射时间是15秒以前的日志,但是本方案的要求是,只需要它跟当前时间错开5秒以上就可以了,所以,超过5秒的,都可以设置为5秒。
在源端数据库开始工作后,数据交互线程按照预设的时间间隔对源端数据库进行轮询,获取源端数据库当前最大的日志序列号和当前时间,将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表中。
在实际应用场景下,日志序列号随着数据库的运行严格的递增,因此,采用轮询的方式获取源端数据库当前最大的日志序列号,可以获取到源端数据库所产生的最新日志记录LSN和查询时当前时间的映射关系。
步骤103:从日志文件中读取待同步日志记录,获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间。
在本实施例中,日志文件读取线程从日志文件中读取待同步日志记录,获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间。
由于在步骤101中,只获取一个轮询区间内的最大日志序列号,还有大量的日志序列号所属的时间没有存储在LSN信息链表中,那么可以通过对比日志序列号大小的方式,从LSN信息链表中确定其他日志序列号所属的写入时间。具体地,从日志文件中读取待同步日志记录,获取所述待同步日志记录的日志序列号LSN0;从所述LSN信息链表中查找最接近于所述日志序列号LSN0,且大于所述日志序列号LSN0的目标日志序列号;获取所述目标日志序列号对应的时间;将所述目标日志序列号对应的时间设置为所述待同步日志记录所属的写入时间。
例如,LSN信息连表中存放的LSN是以秒为单位组织的,假定轮询间隔为1秒,而允许的最小延时为5秒的话,LSN信息链表的最大长度为10,那么LSN信息链表中存放的就是最近10秒的10个LSN。当日志读取线程读取一个日志以后,取得它的LSN,在LSN链表中定位它的所属时间,如果这个LSN比链表中第一个LSN还要小,那说明这个LSN对应的日志肯定是10秒以前的,它的日志时间就可以设置为第一个LSN所属的时间,该LSN所属的时间与当前***时间之间的时间差值大于10秒,将时间差值跟最小延时5秒去对比,大于5秒,直接投递出去;如果LSN大于链表中第二个LSN但小于第三个LSN,那么该LSN日志对应的时间就可以设定为第三个LSN所属的时间,该LSN所属的时间与当前***时间之间的时间差值为8秒,大于最小延时5秒对比,直接投递;如果LSN大于链表上第5个LSN,但小于第6个LSN,那么该LSN日志对应的时间为第6个LSN所属的时间,该LSN所属的时间与当前***时间之间的时间差值为5秒,等于最小延时5秒了,这时候就不能投递,等LSN信息链表更新了以后再次计算时间差,等时间差大于5秒了才能投递。
步骤104:根据所述待同步日志记录所属的写入时间和当前***时间之间的差值大小,进行策略性日志读取和同步。
在本实施例中,根据所述待同步日志记录所属的写入时间和当前***时间之间的差值大小,进行策略性日志读取和同步。
下面结合图2,其中,在图2中步骤101~步骤103的具体过程与前文描述相同,在此不再赘述,步骤104具体包括步骤1041~步骤1044,下面结合步骤1041~步骤1044具体说明步骤104的实现过程。
步骤1041:判断所述待同步日志记录所属的写入时间和当前***时间之间的差值是否大于最小延时时间。
其中,最小延时时间依据同步***所允许的最小同步延时时间而定,依据实际***而定,在此,不做具体限定。
步骤1042:若大于,将所述待同步日志记录同步至目的端,并从日志文件中获取下一个待同步日志记录后,执行步骤103中,所述获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间,以进行策略性日志读取和同步。
在本实施例中,若所述待同步日志记录所属的写入时间和当前***时间之间的差值大于最小延时时间,则对所述待同步日志记录进行解析后,将所述待同步日志记录同步至目的端。
然后,从日志文件中取出下一个日志记录,作为待同步日志记录,获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间,以进行策略性日志读取和同步。
步骤1043:若不大于,则暂停日志读取,并以轮询的方式计算所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值。
在本实施例中,若所述待同步日志记录所属的写入时间和当前***时间之间的差值不大于最小延时时间,暂停日志读取,并以轮询的方式计算所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值。
具体地,按照设定的时间间隔获取所述日志文件中当前读取日志记录,并获取当前读取日志记录的日志序列号,再基于所述LSN信息链表获取当前读取日志记录所属的写入时间,计算并判断所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值是否大于最小延时时间,若所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值不小于最小延时时间时,执行步骤1044,若小于,则继续轮询。
步骤1044:当所述日志文件中当前读取日志记录的写入时间与当前***时间之间的差值不小于最小延时时间时,从日志文件中获取下一个待同步日志记录后,执行所述获取所述待同步日志记录的日志序列号,基于所述LSN信息链表获取所述待同步日志记录所属的写入时间,以进行策略性日志读取和同步。
在本发明中,为了避免数据同步进程和数据库日志写入进程的日志读写冲突,必须防止这两个进程在同一时刻同时访问同一个文件中相同偏移的数据。为了达到这个目的,数据同步***通过在数据库中定时查询数据库的当前最大的日志序列号,然后把获取的日志序列号和当前时间进行关联后,添加在LSN信息链表中,数据同步***在读取日志文件时,需要拿当前待同步日志记录中的日志序列号和LSN信息链表中的值进行对比,定位到该日志记录对应的写入时间,从而计算待同步日志记录和当前数据库最新的日志之间的时间差,让这个时间差永远保持在一个设定值范围之外,不同的时间对应不同的LSN,而不同的LSN则对应不同的日志文件位置,那么通过控制时间差,读的日志所属的时间永远落后于当前***的最新日志,那么就可以保证读取的文件位置永远落在写入的位置后面,可以有效的防止数据同步进程和数据库日志写入进程对日志文件的读写访问产生冲突。
在实际应用场景下,有些应用***是白天业务量很大,而到了晚上业务量很小,在这种***上数据库到了晚上闲的时候写入操作非常的少,导至数据库的LSN一直不推进,而这时同步进程则不会停止,它依然会不断的轮询当前数据库的最大LSN和最新的时间。如果数据库LSN不推进,那么就会出现一个LSN映射到多个不同时间里。这种环境下,那么通过LSN在LSN链表中定们时间并计算时间差的方法就不准确了,所以通过更新辅助表的方式在数据库清闲的时候来推进它的LSN,这样子才能保证轮询添加的LSN值在LSN信息链表中LSN和时间的映射关系不重复。
在优选的实施例中,在数据库空闲时推进日志,数据库交互线程启动时还需要在数据库中初始化一张用来推进日志的辅助表,以便在数据库空闲时通过对辅助表的操作来推进日志。其中,建立辅助表后,需要先初始化一行数据,后面通过更新这行数据来推进数据库日志。
在优选的实施例中,首先,对源端数据库进行轮询,获取源端数据库当前最大的日志序列号和当前时间,然后,判断所述当前最大的日志序列号与前一次获取到的日志序列号是否相等;若相等,则通过更新辅助表的方式推进日志,具体地,建立所述辅助表,并在所述辅助表中初始化一行目标数据;对所述目标数据执行更新操作后提交,以推进所述源端数据库日志;若不相等,则将所述当前最大的日志序列号和所述当前时间建立关联后,添加至LSN信息链表中。
在实际应用场景下,辅助表相关的日志对于目的端而言是无用的数据,无需将其同步至目的端,因此,需要将与辅助表相关的日志进行过滤。在优选的实施例中,从所述日志文件中读取日志记录,获取所述日志记录所针对的对象;当所述日志记录所针对的对象是所述辅助表时,直接过滤所述日志记录,其中,可以通过对象ID(例如,表ID)确定日志记录所针对的对象;当所述日志记录所针对的对象不是所述辅助表时,将所述日志记录标记为待同步日志记录。
在另一实际应用场景下,随着数据同步的推进,LSN信息链表的过期信息也随着增加,需要及时清理,以释放内存。在可选的实施例中,所述日志读取方法还包括:在所述待同步日志记录完成同步后,将所述LSN信息链表中关于所述待同步日志记录的信息删除。具体地,将所述LSN信息链表中小于所述目标序列号的相关信息删除。
在本实施例中,日志文件读取线程在读取日志文件时,只有在读取数据库的在线日志文件时才需要判断日志记录的日志序列号和当前数据库日志的最大日志序列号之间的时间差,通过时间差来错开数据同步进程和数据库进程对日志文件访问的位置,这样可以有效的预防读写冲突的产生,一方面提高了日志读取的可靠性,另一方面也降低了布署数据同步***给数据库运行带来的风险。
实施例2:
基于前述实施例1,在此,以ORACLE为例,举例说明前述实施例1的实现过程:
在数据库A和数据库B上搭建一套数据同步***,并设定数据同步的最小延时为Y秒,设定轮询数据库日志序列号的时间间隔为Z秒,并且源端数据同步***在数据库A上创建有用来推进日志的辅助表T(C INT)。
源端日志同步***的数据库交互过程如下:
(1)数据库交互线程每隔Z秒,从源数据库中通过语句获取当前数据库最大的日志LSN和当前时间,获取的SQL为select dbms_flashback.get_system_change_number,sysdate from dual;得到日志序列号LSN和时间的值为LSN1和TIME1。
步骤(2)把LSN1和TIME1保存到LSN信息链连中,并判断LSN1和上一次获取的值是否相等,不等则跳到步骤(1),继续下一个轮询,否则跳到步骤(3)。
(3)发现这次查询到的LSN和上次相等时,则更新辅助表T来推进日志LSN,通过执行BEGIN UPDATE T SET C=1;COMMIT;END;语句可以强制数据库日志往前推进,促使日志读取线程也能跟进,然后跳到(1)继续下一个轮询。
日志文件读取线程过程如下:
(1)日志文件读取线程从日志文件中读取一个日志记录,提取日志记录中的LSN值。
(2)在LSN信息链表中定位它所属的时间,定位到时间并求得它和***当前时间之间的差X秒,判断X和最小延时时间Y的大小,当X大于Y时,跳到步骤(1)继续读取下一条日志,否则跳到步骤(3);
(3)对日志记录解析以后同步,然后暂停日志读取并轮询的计算当前读取日志记录的时间和当前***时间之差X,直到当X大于等于Y时跳到步骤(1)继续读取下一个日志。
实施例3:
请参阅图4,图4是本发明实施例提供的一种数据同步***的结构示意图。本实施例的数据同步***包括一个或多个处理器41以及存储器42。其中,图4中以一个处理器41为例。
处理器41和存储器42可以通过总线或者其他方式连接,图4中以通过总线连接为例。
存储器42作为一种基于日志读取方法的非易失性计算机可读存储介质,可用于存储非易失性软件程序、非易失性计算机可执行程序以及模块,上述实施例的方法以及对应的程序指令。处理器41通过运行存储在存储器42中的非易失性软件程序、指令以及模块,从而执行各种功能应用以及数据处理,实现前述实施例的方法。
其中,存储器42可以包括高速随机存取存储器,还可以包括非易失性存储器,例如至少一个磁盘存储器件、闪存器件、或其他非易失性固态存储器件。在一些实施例中,存储器42可选包括相对于处理器41远程设置的存储器,这些远程存储器可以通过网络连接至处理器41。上述网络的实例包括但不限于互联网、企业内部网、局域网、移动通信网及其组合。
值得说明的是,上述装置和***内的模块、单元之间的信息交互、执行过程等内容,由于与本发明的处理方法实施例基于同一构思,具体内容可参见本发明方法实施例中的叙述,此处不再赘述。
本领域普通技术人员可以理解实施例的各种方法中的全部或部分步骤是可以通过程序来指令相关的硬件来完成,该程序可以存储于一计算机可读存储介质中,存储介质可以包括:只读存储器(Read Only Memory,简写为ROM)、随机存取存储器(RandomAccessMemory,简写为RAM)、磁盘或光盘等。
本领域的技术人员容易理解,以上所述仅为本发明的较佳实施例而已,并不用以限制本发明,凡在本发明的精神和原则之内所作的任何修改、等同替换和改进等,均应包含在本发明的保护范围之内。