一种消息队列收发系统及方法与流程

文档序号:18475161发布日期:2019-08-20 20:55阅读:476来源:国知局
一种消息队列收发系统及方法与流程

本发明涉及一种消息队列收发系统及方法,属于计算机技术领域。



背景技术:

随着公司业务的快速增长,传统的单体应用架构很难满足业务快速增长的要求,需要进行服务化改造,按照业务等要素将原来庞大的单体应用拆分成不同的服务。那么在进行服务化改造之前首先就是面临是服务化基础设施的技术选型,其中最重要的就是服务之间的通信中间件。一般来讲服务之间的通信可以分为同步方式和异步方式。同步的方式的代表就是rpc,异步方式的代表就是消息队列(messagequeue),mq在当时也有很多开源的选择:rabbitmq,activemq,kafka,metaq(rocketmq的前身)。首先因为技术栈我们排除了erlang开发的rabbitmq,而kafka以及java版kafka的metaq在当时还并不成熟和稳定。而activemq已经有很多应用在使用了,但是使用过程中并不一帆风顺:宕机,消息丢失,消息堵塞等问题屡见不鲜,而且activemq发展多年,代码也非常复杂,想要完全把控也不容易。

在电商交易中数据的一致性是非常关键的要素。那么必须提供一致性保证。供一致性保证又分为两个方面:发消息时我们如何确保业务操作和发消息是一致的,也就是不能出现业务操作成功消息未发出或者消息发出了但是业务并没有成功的情况。

因此,建立一套完善的消息队列管理平台,保证交易顺畅和为用户提供稳定服务,在面对各大企业业务快速增长的情况下,迫在眉睫。



技术实现要素:

为解决上述问题,本发明的目的在于提供一种消息队列收发系统及方法,包括程序执行模块,用于开启本地事务以及事务提交、执行业务操作、消息收发和管理;服务器,用于接收任务模块和程序执行模块发送的消息并回应消息;消息数据库,用于接收程序执行模块和任务模块发送的消息并进行处理事务;任务模块,用于向服务器发送消息并对消息数据库中的消息执行扫描和删除操作。

本发明解决其问题所采用的技术方案一方面是:一种消息队列收发系统,其特征在于,包括:程序执行模块,用于开启本地事务以及事务提交、执行业务操作、消息收发和管理;服务器,用于接收任务模块和程序执行模块发送的消息并回应消息;消息数据库,用于接收程序执行模块和任务模块发送的消息并进行处理事务;任务模块,用于向服务器发送消息并对消息数据库中的消息执行扫描和删除操作。

进一步的,所述消息数据库还包括共享接口模块,用于共享同一端口并在同一事务中运行对应代码。

进一步的,所述服务器还包括存储模型模块,用于将服务器接收到的消息分发给处理单元,处理单元将处理后的消息分发给对应的用户接口。

进一步的,所述存储模型模块还包括:映射单元,用于动态映射处理单元与用户接口的逻辑关系;耦合单元,用于管理和建立处理单元与用户接口的耦合关系。

进一步的,所述存储模型模块还包括:延时单元,用于控制消息在一定时间内延时发送,其中一定时间可自定义。

进一步的,所述延时单元还包括:第一存储子单元,用于在磁盘中以一定时间为刻度,在每个刻度生成对应的日志文件,其中一定时间可自定义;第二存储子单元,用于在内存中实时监测消息,当消息的投递时间即将到来的时候,会将这个刻度的消息索引,从磁盘文件加载到内存中,其中消息索引包括但不限于偏移量和投递时间。

本发明解决其问题所采用的技术方案另一方面是:一种消息队列收发方法,其特征在于,包括以下步骤:s100、程序执行模块开启本地事务以及事务提交、执行业务操作并将事务消息发送给消息数据库和服务器;s200、服务器接收任务模块发送的事务消息,若服务器接收事物信息成功并向程序执行模块回传反馈后,程序执行模块向消息数据库发送删除事务消息的命令,否则执行步骤s300;s300、任务模块向消息数据库中的消息执行扫描并向服务器发送对应事务消息,若程序执行模块成功接收到服务器回传反馈后,任务模块删除消息数据库中存储的对应事务消息,否则反复向消息数据库中的消息执行扫描并向服务器发送对应事务消息。

进一步的,所述s200还包括:s210、服务器接收到的消息分发给处理单元,处理单元将处理后的消息分发给对应的用户接口。

进一步的,所述s200还包括:s210、处理单元与用户接口建立耦合关系和逻辑关系;s220、处理单元将处理后的消息映射给建立耦合关系的对应用户接口。

进一步的,所述s200还包括处理单元将处理后的消息延时一定时间后发送给对应用户接口,其中一定时间可自定义。

本发明的有益效果是:提供一套完善的消息队列管理平台,保证交易顺畅和为用户提供稳定服务,提供一致性保证,确保业务操作和发消息是一致的,同时保证消息的送达和及时反馈,减少消息冗余。

附图说明

图1是根据本发明优选实施例的系统结构示意图;

图2是根据本发明优选实施例的方法流程示意图;

图3是根据本发明优选实施例的消息数据库示意图;

图4是根据本发明优选实施例的存储模型模块中的映射单元示意图;

图5是根据本发明优选实施例的存储模型模块中的延时单元示意图。

具体实施方式

以下将结合实施例和附图对本发明的构思、具体结构及产生的技术效果进行清楚、完整的描述,以充分地理解本发明的目的、方案和效果。

需要说明的是,如无特殊说明,当某一特征被称为“固定”、“连接”在另一个特征,它可以直接固定、连接在另一个特征上,也可以间接地固定、连接在另一个特征上。此外,本公开中所使用的上、下、左、右等描述仅仅是相对于附图中本公开各组成部分的相互位置关系来说的。在本公开中所使用的单数形式的“一种”、“所述”和“该”也旨在包括多数形式,除非上下文清楚地表示其他含义。此外,除非另有定义,本文所使用的所有的技术和科学术语与本技术领域的技术人员通常理解的含义相同。本文说明书中所使用的术语只是为了描述具体的实施例,而不是为了限制本发明。本文所使用的术语“和/或”包括一个或多个相关的所列项目的任意的组合。

应当理解,尽管在本公开可能采用术语第一、第二、第三等来描述各种元件,但这些元件不应限于这些术语。这些术语仅用来将同一类型的元件彼此区分开。例如,在不脱离本公开范围的情况下,第一元件也可以被称为第二元件,类似地,第二元件也可以被称为第一元件。本文所提供的任何以及所有实例或示例性语言(“例如”、“如”等)的使用仅意图更好地说明本发明的实施例,并且除非另外要求,否则不会对本发明的范围施加限制。

参照图1是根据本发明优选实施例的系统结构示意图,

1.begintx开启本地事务

2.dowork执行业务操作

3.insertmessage向同实例消息库插入消息

4.endtx事务提交

5.sendmessage网络向server发送消息

6.reponseserver回应消息

7.deletemessage如果server回复成功则删除消息

8.scanmessages补偿任务扫描未发送消息

9.sendmessage补偿任务补偿消息

10.deletemessages补偿任务删除补偿成功的消息

参照图2是根据本发明优选实施例的方法流程示意图,

s100、程序执行模块开启本地事务以及事务提交、执行业务操作并将事务消息发送给消息数据库和服务器;

s200、服务器接收任务模块发送的事务消息,若服务器接收事物信息成功并向程序执行模块回传反馈后,程序执行模块向消息数据库发送删除事务消息的命令,否则执行步骤s300;

s300、任务模块向消息数据库中的消息执行扫描并向服务器发送对应事务消息,若程序执行模块成功接收到服务器回传反馈后,任务模块删除消息数据库中存储的对应事务消息,否则反复向消息数据库中的消息执行扫描并向服务器发送对应事务消息。

s200还包括:s210、服务器接收到的消息分发给处理单元,处理单元将处理后的消息分发给对应的用户接口。

s200还包括:s210、处理单元与用户接口建立耦合关系和逻辑关系;s220、处理单元将处理后的消息映射给建立耦合关系的对应用户接口。

s200还包括处理单元将处理后的消息延时一定时间后发送给对应用户接口,其中一定时间可自定义。

公司提供了旅游产品在线预订服务,那么就涉及电商交易,在电商交易中我们认为数据的一致性是非常关键的要素。那么我们的mq必须提供一致性保证。

mq提供一致性保证又分为两个方面:发消息时我们如何确保业务操作和发消息是一致的,也就是不能出现业务操作成功消息未发出或者消息发出了但是业务并没有成功的情况。举例来说,支付服务使用消息通知出票服务,那么不能出现支付成功,但是消息没有发出,这会引起用户投诉;但是也不能出现支付未成功,但是消息发出最后出票了,这会导致公司损失。总结一下就是发消息和业务需要有事务保证。一致性的另一端是消费者,比如消费者临时出错或网络故障,我们如何确保消息最终被处理了。那么我们通过消费ack和重试来达到最终一致性。

而服务端设计,经过对未来数据的预估我们选择数据库作为mqserver的消息存储,但是随着mq在各系统中的大量应用,就不仅限于交易场景了,而且大家都期望所有场景中只使用一套api,所以后来消息量迅速增长,迫使我们对存储模型进行了重新设计。再加上旅游产品预定的特征,大部分预定都是未来某个时间点的,这个时间可长可短,短的话可能是几个小时,长的话可能是半年以上,那么我们对延时消息的需求也很强烈。

接下来会从客户端一致性设计和服务端存储模型两方面进行讨论。

客户端一致性

提到一致性,大家肯定就想到事务,而一提到事务,肯定就想到关系型数据库,那么我们是不是可以借助关系型db里久经考验的事务来实现这个一致性呢。我们以mysql为例,对于mysql中同一个实例里面的db,如果共享相同的connection的话是可以在同一个事务里的。以下图为例,我们有一个mysql实例监听在3306端口上,然后该实例上有a,b两个db,那么下面的伪代码是可以跑在同一个事务里的:

参照图3是根据本发明优选实施例的消息数据库示意图,

begintransaction

insertintoa.tbl1(name,age)values('admin',18);

insertintob.tbl2(num)values(20);

endtransaction

有了这层保证,我们就可以透明的实现业务操作和消息发送在同一个事务里了,首先我们在公司所有mysql实例里初始化出一个messagedb,这个可以放到自动化流程中,对应用透明。然后我们只要将发消息与业务操作放到同一个db事务里即可。

一个实际的场景:在支付场景中,支付成功后我们需要插入一条支付流水,并且发送一条支付完成的消息通知其他系统。那么这里插入支付流水和发送消息就需要是一致的,任何一步没有成功最后都会导致问题。那么就有下面的代码:

上面的代码可以用下面的伪代码解释:

实际上在producer.sendmessage执行的时候,消息并没有通过网络发送出去,而仅仅是往业务db同一个实例上的消息库插入了一条记录,然后注册事务的回调,在这个事务真正提交后消息才从网络发送出去,这个时候如果发送到server成功的话消息会被立即删除掉。而如果消息发送失败则消息就留在消息库里,这个时候我们会有一个补偿任务会将这些消息从消息库里捞出然后重新发送,直到发送成功。整个流程就如图1所示,

服务端存储模型

分析了客户端为了一致性所作的设计后,我们再来看看服务端的存储设计。我会从两个方面来介绍:类似kafka之类的基于partition存储模型有什么问题,以及我们是如何解决的。

基于partition存储模型的问题

我们都知道kafka和rocketmq都是基于partition的存储模型,也就是每个subject分为一个或多个partition,而server收到消息后将其分发到某个partition上,而consumer消费的时候是与partition对应的。比如,我们某个subjecta分配了3个partition(p1,p2,p3),有3个消费者(c1,c2,c3)消费该消息,则会建立c1-p1,c2-p2,c3-p3这样的消费关系。

那么如果我们的consumer个数比partition个数多呢?则有的consumer会是空闲的。

而如果partition个数比consumer个数多呢?则可能存在有的consumer消费的partition个数会比其他的consumer多的情况。

那么合理的分配策略只有是partition个数与consumer个数成倍数关系。

以上都是基于partition的mq所带来的负载均衡问题。因为这种静态的绑定的关系,还会导致consumer扩容缩容麻烦。也就是使用kafka或者rocketmq这种基于partition的消息队列时,如果遇到处理速度跟不上时,光简单的增加consumer并不能马上提高处理能力,需要对应的增加partition个数,而特别在kafka里partition是一个比较重的资源,增加太多parition还需要考虑整个集群的处理能力;当高峰期过了之后,如果想缩容consumer也比较麻烦,因为partition只能增加,不能减少。

跟扩容相关的另外一个问题是,已经堆积的消息是不能快速消费的。比如开始的时候我们分配了2个partition,由2个consumer来消费,但是突然发送方大量发送消息(这个在日常运维中经常遇到),导致消息快速的堆积,这个时候我们如何能快速扩容消费这些消息呢?其实增加partition和consumer都是没有用的,增加的consumer爱莫能助,因为堆积的那3个partition只能由2个consumer来消费,这个时候你只能纵向扩展,而不能横向扩展,而我们都知道纵向扩展很多时候是不现实的,或者执行比较重的再均衡操作。

qmq消息队列存储模型

现在公司的系统架构基本上都是消息驱动的,也就是绝大多数业务流程都是靠消息来驱动,那么这样的架构有什么特征呢:

·消息主题特别多现在生产上已有4w+消息主题。这是业务中使用的消息与数据流处理中使用的最大的不同,数据流中一般消息主题少,但是每个消息主题的吞吐量都极大。而业务中的消息是主题极多,但是有很多主题他的量是极小的。

·消息消费的扇出大也就是一个消息主题有几十个甚至上百个不同的应用订阅是非常常见的。以去哪儿酒店订单状态变更的消息为例,目前有将近70多个不同的系统来订阅这个消息。

结合前面对基于partition的存储模型的讨论,我们觉得这种存储模型不太容易符合我们的需求。

虽然我们并不想采用基于partition的存储模型,但是kafka和rocketmq里很多设计我们还是可以学习的:

·顺序append文件,提供很好的性能

·顺序消费文件,使用offset表示消费进度,不用给每个消息记录消费状态,成本极低

·将所有subject的消息合并在一起,减少parition数量,单一集群可以支撑更多的subject(rocketmq)

在设计qmq的存储模型时,觉得这几点是非常重要的。那如何在不使用基于partition的情况下,又能得到这些特性呢?正所谓有前辈大师说:计算机中所有问题都可以通过添加一个中间层来解决,一个中间层解决不了那就添加两个。

通过添加一层拉取的log(pulllog)来动态映射consumer与partition的逻辑关系,这样不仅解决了consumer的动态扩容缩容问题,还可以继续使用一个offset表示消费进度。而pulllog与consumer一一对应。

图4是qmq的存储模型中映射单元示意图,

方框上方的数字,表示该方框在自己log中的偏移,而方框内的数字是该项的内容。比如messagelog方框上方的数字:3,6,9表示这几条消息在messagelog中的偏移。而consumelog中方框内的数字3,6,9,20正对应着messzgelog的偏移,表示这几个位置上的消息都是topic1的消息,consumelog方框上方的1,2,3,4表示这几个方框在consumelog中的逻辑偏移。下面的pulllog方框内的内容对应着consumelog的逻辑偏移,而pulllog方框外的数字表示pulllog的逻辑偏移。

这样存储中有三种重要的log:

·messagelog所有subject的消息进入该log,消息的主存储

·consumelogconsumelog存储的是messagelog的索引信息

·pulllog每个consumer拉取消息的时候会产生pulllog,pulllog记录的是拉取的消息在consumelog中的sequence

那么消费者就可以使用pulllog上的sequence来表示消费进度,这样一来我们就解耦了consumer与partition之间的耦合关系,两者可以任意的扩展。

延迟消息队列存储模型

除了对实时消息的支持,qmq还支持了任意时间的延时消息,在开源版本的rocektmq里提供了多种固定延迟level的延时消息支持,也就是你可以发送几个固定的延时时间的延时消息,比如延时10s,30s…,但是基于我们现有的业务特征,我们觉得这种不同延时level的延时消息并不能满足我们的需要,我们更多的是需要任意时间延时。在ota场景中,客人经常是预订未来某个时刻的酒店或者机票,这个时间是不固定的,我们无法使用几个固定的延时level来实现这个场景。

我们的延时/定时消息使用的是两层hashwheeltimer来实现的。第一层位于磁盘上,每个小时为一个刻度,每个刻度会生成一个日志文件,根据业务特征,我们觉得支持两年内任意时间延时就够了,那么最多会生成2*366*24=17568个文件。第二层在内存中,当消息的投递时间即将到来的时候,会将这个小时的消息索引(偏移量,投递时间等)从磁盘文件加载到内存中的hashwheeltimer上,参照图5是根据本发明优选实施例的存储模型模块中的延时单元示意图,

在延时/定时消息里也存在三种log:

·messagelog和实时消息里的messagelog类似,收到消息后append到该log,append成功后就立即返回

·schedulelog按照投递时间组织,每个小时一个。该log是回放messagelog后根据延时时间放置对应的log上,这是上面描述的两层hashwheeltimer的第一层,位于磁盘上

·dispatchlog延时/定时消息投递后写入,主要用于在应用重启后能够确定哪些消息已经投递。

应当认识到,本发明的实施例可以由计算机硬件、硬件和软件的组合、或者通过存储在非暂时性计算机可读存储器中的计算机指令来实现或实施。所述方法可以使用标准编程技术-包括配置有计算机程序的非暂时性计算机可读存储介质在计算机程序中实现,其中如此配置的存储介质使得计算机以特定和预定义的方式操作——根据在具体实施例中描述的方法和附图。每个程序可以以高级过程或面向对象的编程语言来实现以与计算机系统通信。然而,若需要,该程序可以以汇编或机器语言实现。在任何情况下,该语言可以是编译或解释的语言。此外,为此目的该程序能够在编程的专用集成电路上运行。

此外,可按任何合适的顺序来执行本文描述的过程的操作,除非本文另外指示或以其他方式明显地与上下文矛盾。本文描述的过程(或变型和/或其组合)可在配置有可执行指令的一个或多个计算机系统的控制下执行,并且可作为共同地在一个或多个处理器上执行的代码(例如,可执行指令、一个或多个计算机程序或一个或多个应用)、由硬件或其组合来实现。所述计算机程序包括可由一个或多个处理器执行的多个指令。

进一步,所述方法可以在可操作地连接至合适的任何类型的计算平台中实现,包括但不限于个人电脑、迷你计算机、主框架、工作站、网络或分布式计算环境、单独的或集成的计算机平台、或者与带电粒子工具或其它成像装置通信等等。本发明的各方面可以以存储在非暂时性存储介质或设备上的机器可读代码来实现,无论是可移动的还是集成至计算平台,如硬盘、光学读取和/或写入存储介质、ram、rom等,使得其可由可编程计算机读取,当存储介质或设备由计算机读取时可用于配置和操作计算机以执行在此所描述的过程。此外,机器可读代码,或其部分可以通过有线或无线网络传输。当此类媒体包括结合微处理器或其他数据处理器实现上文所述步骤的指令或程序时,本文所述的发明包括这些和其他不同类型的非暂时性计算机可读存储介质。当根据本发明所述的方法和技术编程时,本发明还包括计算机本身。

计算机程序能够应用于输入数据以执行本文所述的功能,从而转换输入数据以生成存储至非易失性存储器的输出数据。输出信息还可以应用于一个或多个输出设备如显示器。在本发明优选的实施例中,转换的数据表示物理和有形的对象,包括显示器上产生的物理和有形对象的特定视觉描绘。

以上所述,只是本发明的较佳实施例而已,本发明并不局限于上述实施方式,只要其以相同的手段达到本发明的技术效果,凡在本发明的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本发明保护的范围之内。在本发明的保护范围内其技术方案和/或实施方式可以有各种不同的修改和变化。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1