本申请涉及网络服务技术领域,尤其涉及一种实现分布式系统中延时消息的方法和装置、设备及存储介质。
背景技术:
延时消息指的是生产者将消息发送到消息服务端,但并不期望这条消息马上投递,而是延迟一定时间后才投递到消费者进行消费。在实现延时消息的相关技术中,能够支持任意时间延时消息的技术通常采用rabbitmq来实现。但是,采用rabbitmq实现任意时间延时消息时,需要在项目中额外引入消息中间件,从而不易于维护。
技术实现要素:
有鉴于此,本申请提出了一种实现分布式系统中延时消息的方法,不需要额外引入消息中间件,从而有利于系统维护。
根据本申请的一方面,提供了一种实现分布式系统中延时消息的方法,包括:
在服务启动时,拉取zookeeper中存储的所有延时消息,并将拉取到的所有所述延时消息存放到延时队列中;
基于所述延时队列中各所述延时消息的投递时间执行相应的消费逻辑。
在一种可能的实现方式中,在将拉取到的所有所述延时消息存放到所述延时队列之后,还包括:
启动所述zookeeper中的watcher线程,通过watcher线程监听所述zookeeper中是否存在新增节点,并在监听到所述zookeeper中存在所述新增节点时,将所述新增节点所对应的新增延时消息拉取到所述延时队列中。
在一种可能的实现方式中,将拉取到的所有所述延时消息存放到延时队列中时,各所述延时消息根据投递时间按序排列。
在一种可能的实现方式中,基于所述延时队列中各所述延时消息的投递时间执行相应的消费逻辑,包括:
在第一延时消息的投递时间到时,启动消费线程,由所述消费线程根据所述第一延时消息的节点id获取分布式锁;
在获取到所述第一延时消息的分布式锁后,进行所述第一延时消息的消费。
在一种可能的实现方式中,在获取到所述第一延时消息的分布式锁后,还包括:
判断所述第一延时消息在所述zookeeper中是否存在对应的节点;
在判断出存在对应的节点时,则执行所述第一延时消息的消费逻辑。
在一种可能的实现方式中,所述延时队列通过delayqueue实现。
根据本申请的一方面,还提供了一种实现分布式系统中延时消息的装置,包括消息拉取模块和消息消费模块;
所述消息拉取模块,被配置为在服务启动时,拉取zookeeper中存储的所有延时消息,并将拉取到的所有所述延时消息存放到延时队列中;
所述消息消费模块,被配置为基于所述延时队列中各所述延时消息的投递时间执行相应的消费逻辑。
在一种可能的实现方式中,还包括watcher线程启动模块;
所述watcher线程启动模块,被配置为在所述消息拉取模块将所有所述延时消息存放到所述延时队列之后,启动所述zookeeper中的watcher线程,通过watcher线程监听所述zookeeper中是否存在新增节点,并在监听到所述zookeeper中存在所述新增节点时,将所述新增节点所对应的新增延时消息拉取到所述延时队列中。
根据本申请的另一方面,还提供了一种实现分布式系统中延时消息的设备,包括:
处理器;
用于存储处理器可执行指令的存储器;
其中,所述处理器被配置为执行所述可执行指令时实现前面任一所述的方法。
根据本申请的另一方面,还提供了一种非易失性计算机可读存储介质,其上存储有计算机程序指令,所述计算机程序指令被处理器执行时实现前面任一所述的方法。
通过以zookeeper作为服务端,进行所有延时消息的存储,从而在进行延时消息的实现时,可以直接调用zookeeper中相应的线程。并且,由于在各项订单项目中本身就使用了zookeeper,因此不需要再额外引用新的中间件。这就有效简化了延时消息实现的系统架构。
根据下面参考附图对示例性实施例的详细说明,本申请的其它特征及方面将变得清楚。
附图说明
包含在说明书中并且构成说明书的一部分的附图与说明书一起示出了本申请的示例性实施例、特征和方面,并且用于解释本申请的原理。
图1示出本申请实施例的实现分布式系统中延时消息的方法的流程图;
图2示出用于本申请实施例的实现分布式系统中延时消息的方法的架构示意图;
图3示出本申请实施例的实现分布式系统中延时消息的装置的结构框图;
图4示出本申请实施例的实现分布式系统中延时消息的设备的结构框图。
具体实施方式
以下将参考附图详细说明本申请的各种示例性实施例、特征和方面。附图中相同的附图标记表示功能相同或相似的元件。尽管在附图中示出了实施例的各种方面,但是除非特别指出,不必按比例绘制附图。
在这里专用的词“示例性”意为“用作例子、实施例或说明性”。这里作为“示例性”所说明的任何实施例不必解释为优于或好于其它实施例。
另外,为了更好的说明本申请,在下文的具体实施方式中给出了众多的具体细节。本领域技术人员应当理解,没有某些具体细节,本申请同样可以实施。在一些实例中,对于本领域技术人员熟知的方法、手段、元件和电路未作详细描述,以便于凸显本申请的主旨。
图1示出根据本申请一实施例的实现分布式系统中延时消息的方法的流程图。如图1所示,该方法包括:步骤s100,在服务启动时,拉取zookeeper中存储的所有延时消息,并将拉取到的所有延时消息存放到延时队列中。其中,需要说明的是,在本申请实施例的方法中,各延时消息保存在zookeeper中时均以持久节点的方式进行保存,以保证各延时消息的持久性,如此即使在服务端或zookeeper宕机后仍能够保证各延时消息不会被丢失。
也就是说,本申请实施例的实现分布式系统中延时消息的方法,采用zookeeper作为服务端(如图2所示),由zookeeper服务端将所有的延时消息以持久节点的方式进行存储。
然后再通过步骤s200,基于延时队列中各延时消息的投递时间执行相应的消费逻辑。即,在客户端通过实时监测延时队列,在延时队列中的某一延时消息的投递时间到了的时候即可执行该延时消息的消费逻辑。
由此,本申请实施例的实现分布式系统中延时消息的方法,通过以zookeeper作为服务端,进行所有延时消息的存储,从而在进行延时消息的实现时,可以直接调用zookeeper中相应的线程。并且,由于在各项订单项目中本身就使用了zookeeper,因此不需要再额外引用新的中间件。这就有效简化了延时消息实现的系统架构。
其中,还需要指出的是,在本申请实施例的方法中,拉取zookeeper中存储的所有延时消息时,可以采用逐个读取的方式,也可以采用整体读取的方式,此处不进行具体限定。
同时,各延时消息在zookeeper中存储时,不同的延时消息占据不同的节点,并且不同的延时消息通过唯一的节点标识进行标记。
此外,还需要说明的是,延时队列可以通过delayqueue实现。通过delayqueue实现延时队列,从而能够在延时消息的投递时间到达时可以直接执行,这也就保证了延时消息执行时不会出现任何延时的情况,达到了瞬时响应的功能。
在一种可能的实现方式中,延时队列还可以使用netty的hashedwheeltimer组件代替,此处不再进行赘述。
参阅图2,在本申请实施例的方法中,将拉取到的所有延时消息存放到延时队列之后,还包括:启动zookeeper中的watcher线程,通过watcher线程监听zookeeper中是否存在新增节点,并在监听到zookeeper中存在新增节点时,将新增节点所对应的新增延时消息拉取到延时队列中的步骤。
即,通过启动zookeeper中的watcher线程,由watcher线程实现对zookeeper中的节点的实时监视,在zookeeper中出现新增节点时,便将新增节点处的延时消息存放到延时队列中,使得zookeeper中的节点信息与延时队列汇中的延时消息达到实时同步的目的,从而达到延时消息能够准时被执行的目的。
具体的,由watcher线程实现对zookeeper中的节点的实时监视,在zookeeper中出现新增节点时,便将新增节点处的延时消息存放到延时队列中时,可以通过回调的方式来实现。
即,参阅图2,通过实时检测是否有新任务添加,在检测出有新任务添加时,将新任务加入到zookeeper中。与此同时,启动的watcher线程收到zookeeper的回调,通过该回调使得watcher线程确定zookeeper中添加了新增节点,进而再将新增节点处的延时消息拉取到延时队列中。
由此,本申请实施例的方法,在进行延时消息的实现过程中,通过使用zookeeper中的watcher机制,实现了其中一个客户端发送新消息之后能够马上通知到所有客户端的功能。
进一步的,在将所有延时消息存放到延时队列中,以及将新增的延时消息同步到延时队列中时,各延时消息在延时队列中的记录方式可以按照各延时消息的投递时间按序排列。
即,各延时消息在延时队列中存放时,可以按照其对应的投递时间的先后顺序依次排列。在一种可能的实现方式中,各延时消息可以按照各自的投递时间由小到大依次排列。其中,投递时间越早的排在越前面。
更加具体的,在进行延时消息投放到延时队列中时,可以采用两两比较的方式对各延时消息的投递时间进行大小比较,然后根据比较结果进行各延时消息的投放。
同时,在将新增的延时消息投放到延时队列时,则可以直接按照延时队列从前到后的顺序,依次将延时队列中的各延时消息与新增的延时消息进行投递时间的大小比较,然后根据比较结果将新增的延时消息投放到延时队列中。
更进一步的,在本申请实施例的方法中,基于延时队列中各延时消息的投递时间执行相应的消费逻辑,可以通过以下方式来实现。
即,在第一延时消息的投递时间到时,启动消费线程,由消费线程根据第一延时消息的节点id获取分布式锁。在获取到第一延时消息的分布式锁后,进行第一延时消息的消费。此处,本领域技术人员可以理解的是,第一延时消息指的是延时队列中当前达到投递时间的延时消息。
也就是说,本申请实施例的实现分布式系统中延时消息的方法中,在基于延时队列中的各延时消息的投递时间,执行相应的消费逻辑时,是通过启用zookeeper中的消费线程来实现的。
其中,该消费线程会一直阻塞在延时队列上,直到有延时消息的投递时间到了之后,延时队列就会唤醒消费线程。消费线程根据当前到达投递时间的延时消息所对应的节点id去获取分布式锁。在获取到分布式锁之后再进行当前达到投递时间的延时消息的消费。
此处,需要说明的是,消费线程根据延时消息对应的节点id获取分布式锁的方式,可以采用本领域的常规技术手段来实现,此处不再进行赘述。
另外,在一种可能的实现方式中,消费线程获取到分布式锁之后,执行当前达到投递时间的延时消息的消费逻辑之前,还可以先判断一下zookeeper中当前是否存在该延时消息所对应的节点。在判断出该延时消息所对应的节点在zookeeper中存在时,表明当前节点暂时还没有被消费,因此可直接执行该延时消息的消费逻辑。在判断出该延时消息对应的节点不存在时,则表明该节点已经被消费过,因此此时直接将该延时消息丢弃掉,不再执行其对应的消费逻辑。
即,在本申请实施例的方法中,当延时队列中当前达到投递时间的延时消息被消费线程执行之前,先对其在zookeeper中的节点进行是否存在的再次判断,从而有效避免了同一延时消息被重复执行的情况,保证了延时消息投递的准确性。
同时,在上述可能的实现方式中,在判断出当前达到投递时间的延时消息在zookeeper中的节点还存在时,此时执行该延时消息对应的消费逻辑,将该延时消息投递至对应的客户端中后,还包括将zookeeper中该延时消息对应的节点删除的操作,同样进一步地避免了同一延时消息被重复执行的情况。
由此,本申请实施例的实现分布式系统中延时消息的方法,通过以zookeeper作为服务端,并结合delayqueue来实现延时队列,实现了基于zookeeper和delayqueue的相互配合来进行延时消息的投递处理。同时,通过综合zookeeper和delayqueue,并使用zookeeper中的watcher机制进行zookeeper中的延时消息与delayqueue中的延时消息的同步,使得在zookeeper中出现的新增节点均能够全部及时同步到delayqueue中。并且本申请实施例的方法相较于相关技术中采用rabbitmq来实现延时消息的方式,不仅能够支持任意时间的延时消息,还能够支持更长时间的延时消息的实现,从而有效克服了采用rabbitmq来实现延时消息时最大只能实现4294967295毫秒的延时消息的缺陷。
并且,在进行延时队列中的延时消息的消费时,则通过delayqueue来实现延时队列,并使用zookeeper中的消费线程进行延时消息的消费,从而在进行延时消息的投递时不存在任何延时,这也就有效提高了延时消息的响应速率。
为更清楚地说明本申请实施例的实现分布式系统中延时消息的方法,以下以图2所示实施例为例,进行更加详细地说明。
参阅图2,首先,在第①步时,服务启动的时候,会先去zookeeper中拉取所有的延时消息,并存放到delayqueue中。然后,通过第②步,启动watcher线程,持续监听zookeeper中新增的节点。同时,执行第③步,实时监测是否有新的延时任务。并在有新的延时任务添加时,直接将任务放入到zookeeper中。
进而,再通过第④步,当zookeeper中有新的任务添加时,在前面步骤中启动的watcher线程会收到zookeeper的回调,此时就会把这个新增的节点存入delayqueue中。其中,所有的延时任务在delayqueue中,都会根据消息的投递时间排序,越小的时间的排名就越靠前。
同时,在第⑤步中,消费线程会一直阻塞在delayqueue上,直到有延时消息的消费时间(即,投递时间)到了之后,delayqueue就会唤醒消费线程。消费线程拿到延时任务后,先根据节点唯一id去获取分布式锁。获取到分布式锁后,再次判断节点是否存在。当节点存在时,则代表当前节点暂时未被消费,此时执行消费逻辑,当消息消费完毕后,即删除此节点。当节点不存在时,即代表当前节点已经被消费过,则直接丢弃此消息。
需要说明的是,尽管以图1和图2作为示例介绍了如上所述的实现分布式系统中延时消息的方法,但本领域技术人员能够理解,本申请应不限于此。事实上,用户完全可根据个人喜好和/或实际应用场景灵活设定各步骤的具体实现方式,只要能够实现综合zookeeper和delayqueue来实现延时消息即可。
相应的,基于前面任一所述的实现分布式系统中延时消息的方法,本申请还提供了一种实现分布式系统中延时消息的装置。由于本申请的实现分布式系统中延时消息的装置的工作原理与本申请的实现分布式系统中延时消息的方法的原理相同或相似,因此重复之处不再赘述。
参阅图3,本申请提供的实现分布式系统中延时消息的装置100,包括消息拉取模块110和消息消费模块120。其中,消息拉取模块110,被配置为在服务启动时,拉取zookeeper中存储的所有延时消息,并将拉取到的所有延时消息存放到延时队列中。消息消费模块120,被配置为基于延时队列中各延时消息的投递时间执行相应的消费逻辑。
在一种可能的实现方式中,还包括watcher线程启动模块(图中未示出)。其中,watcher线程启动模块,被配置为在消息拉取模块110将所有延时消息存放到延时队列之后,启动zookeeper中的watcher线程,通过watcher线程监听zookeeper中是否存在新增节点,并在监听到zookeeper中存在新增节点时,将新增节点所对应的新增延时消息拉取到延时队列中。
更进一步地,根据本申请的另一方面,还提供了一种实现分布式系统中延时消息设备200。参阅图4,本申请实施例的实现分布式系统中延时消息设备200包括处理器210以及用于存储处理器210可执行指令的存储器220。其中,处理器210被配置为执行可执行指令时实现前面任一所述的实现分布式系统中延时消息方法。
此处,应当指出的是,处理器210的个数可以为一个或多个。同时,在本申请实施例的实现分布式系统中延时消息设备200中,还可以包括输入装置230和输出装置240。其中,处理器210、存储器220、输入装置230和输出装置240之间可以通过总线连接,也可以通过其他方式连接,此处不进行具体限定。
存储器220作为一种计算机可读存储介质,可用于存储软件程序、计算机可执行程序和各种模块,如:本申请实施例的实现分布式系统中延时消息方法所对应的程序或模块。处理器210通过运行存储在存储器220中的软件程序或模块,从而执行实现分布式系统中延时消息设备200的各种功能应用及数据处理。
输入装置230可用于接收输入的数字或信号。其中,信号可以为产生与设备/终端/服务器的用户设置以及功能控制有关的键信号。输出装置240可以包括显示屏等显示设备。
根据本申请的另一方面,还提供了一种非易失性计算机可读存储介质,其上存储有计算机程序指令,计算机程序指令被处理器210执行时实现前面任一所述的实现分布式系统中延时消息方法。
以上已经描述了本申请的各实施例,上述说明是示例性的,并非穷尽性的,并且也不限于所披露的各实施例。在不偏离所说明的各实施例的范围和精神的情况下,对于本技术领域的普通技术人员来说许多修改和变更都是显而易见的。本文中所用术语的选择,旨在最好地解释各实施例的原理、实际应用或对市场中的技术的改进,或者使本技术领域的其它普通技术人员能理解本文披露的各实施例。