一、背景
消息队列:是一种异步通讯的中间件。可以将它理解成邮局,发送者将消息传递到邮局,然后由邮局帮我们发送给具体的消息接收者(消费者),具体发送过程与时间我们无需关心,它也不会干扰我进行其它事情。
跨集群同步:是指2个独立部署的消息队列集群之间进行消息数据的同步。一般用于异地双活等场景,用于支持消息队列双写。
顺序消息:是指消息消费者在进行消息消费时,对消息生产的顺序有要求,例如用户可能要进行一连串的业务步骤,于是投递一系列的顺序消息到消息队列中,然后由消息消费者依次对其进行消费,按步骤完成业务操作。
二、问题
在异地双活消息队列中,需要对2个独立部署的消息队列集群进行消息数据的双向同步。消息队列中除了普通的消息,还有各种特殊的消息,例如延迟消息、顺序消息、重试消息等等。对于跨集群消息同步服务来说,除了要同步普通的消息,还需要对顺序消息进行跨集群双向同步,否则会造成功能的缺失。
顺序消息的本质,是生产消息的时候按顺序写入队列,同时消费消息的时候从队列中顺序消费。为了提升性能和并发能力,消息队列会对同一Topic的消息进行分区,并由用户提供一个分区算法来决定消息所属的分区,因此消息消费的时候只在同一个分区上有序。对于跨集群消息队列同步来说,由于消息源集群和消息目标集群是2个独立的集群,因此它们在对消息进行数据分区的时候,无法保证分区数量一致,另一方面因为环境的不同(算法中可能会引用其它外部变量)所以分区算法也无法同步,所以当一条顺序消息从一个集群同步到另一个集群的时候,会导致消息顺序的丢失。
三、解决方案
本方案提出一种基于源分区标识对消息按目标分区状态进行重新分区的方法,实现跨集群的顺序消息同步。
顺序消息的本质,是生产消息的时候按顺序写入队列,同时消费消息的时候从队列中顺序消费。为了提升性能和并发能力,消息队列会对同一Topic的消息进行分区,并由用户提供一个分区算法来决定消息所属的分区,因此消息消费的时候只在同一个分区上有序。图1为顺序消息原理。
由于同一集群中,主节点和从节点的数据完全一致,因此消息队列中自带的主从复制,不会造成消息顺序的丢失。图2为主从复制中的顺序消息。
对于跨集群消息队列同步来说,由于消息源集群和消息目标集群是2个独立的集群,因此它们在对消息进行数据分区的时候,无法保证分区数量一致,另一方面因为环境的不同(算法中可能会引用其它外部变量)所以分区算法也无法同步,所以当一条顺序消息从一个集群同步到另一个集群的时候,会导致消息顺序的丢失。图3为跨集群消息同步中的顺序消息同步问题。
从其本质上看来,分区算法其实最终会反映到数据分区ID上,因此,虽然消息分区算法无法传递,但是可以考虑在进行跨集群的同步将消息所属的分区ID带上,当消息到达目标集群后,再按该分区ID进行重新分区,即可将消息顺序保留,实现跨集群的顺序消息同步。图4为顺序消息跨集群同步。