MQ顺序消息-项目场景优化

目前许多小伙伴在讨论MQ实现顺序消息时,都会采用以下几个思路:

  •         生产端:创建一条消息,通过网络发送到MQ Server
  •         MQ:将消息存储在topic 的一个分区里
  •         消费端:从分区中拉取消息,消费处理

在这思路之上辅以一些其他配置和操作,能实现MQ顺序消息,但是很明显性能是不够的,下面将结合实际案例来进行分析


先来看一个顺序消息的案例

背景:

        公司作为短信平台,向运营商发送短信后需要记录发送的状态(三个状态流转:已提交运营商->已发送->用户已读)

现状:

        为保证MQ消息顺序性,所以topic只开了一个queue,消费时顺序消费即可,保证了消息状态流转的准确性

问题:

        性能太差,rocketmq集群的性能没有发挥出来,实际性能仅是单broker中单queue所能达到的瓶颈


改造目的:

        提高此业务TPS


初步改造:
        充分利用rocketmq集群的性能,对消息状态保证最终一致性

                1. topic 分 1024queue,分布在rocketmq集群中

                2. 消息生产者不做负载逻辑,直接向topic中发送消息(默认是轮训算法进行路由到具体queue) 

                3. 消息消费者(这里拿mysql 可重复读来举例),在消费到消息后先根据消息唯一ID进行加锁

                        i. 锁到数据,判断当前消息的状态来决定是否处理

                        规则:

                                表中记录为 已提交运营商 或 已发送,MQ消息的状态为 用户已读,则直接修改消息状态为 用户已读

                                表中记录为 用户已读,MQ消息就直接跳过(当消费成功处理)

                                表中记录为 已发送,MQ消息状态为 已提价运行商则跳过

                        ii. 未锁到记录,则直接使用当前MQ消息的状态,后续重复上一步

小结:

        将之前的顺序消息改造为非顺序消息,在消费端去做状态的控制,提升了性能,保证消息状态的最终一致性


进一步优化:

        根据消息ID来作为分区键:

                在一定程度上可以保证局部一致性(生产或消费异常除外「这里会有一些配置项」),不过在上述场景基本没问题,因为本身消息都是有一定间隔时间,异常重试都不会太久,并且有业务逻辑兜底

小结:

        消息发送端修改路由规则,根据消息ID进行分发。

        消费端如多线程消费根据需要决定是否手动进行一次 分组 动作[某些业务同组消息则需要保证顺序性]


到此为止上面案例中的问题已经解决了,那如果有这么一个场景:A B C三个消息必须保证绝对的顺序性呢?显然上述方案就无能为力了,接着往下看

保证消息的绝对一致性:

        可以采用子母单来实现,增加一张log表,等待顺序子单都到达以后再触发任务

使用子母简要的实现思路:

  1. 子单和母单的关系:子单表示某个任务的子任务,而母单则表示整个任务。在处理任务时,首先创建母单,并为每个子任务生成一个对应的子单。子单中可以包含子任务的详细信息,例如子任务的编号、状态等。
  2. 母单的日志表:创建一个日志表用于记录子单的到达情况。每当一个子单到达时,将其记录到日志表中。日志表中的记录可以包含子单的编号、到达时间等信息。
  3. 判断任务触发时机:当子单到达时,将其记录到日志表中。在记录子单到达时,可以检查是否所有的子单都已经到达。如果是,则表示所有子任务已完成,可以触发任务的执行。
  4. 容错处理:在实现过程中,需要考虑容错和异常情况的处理。例如,如果某个子任务在规定的时间内没有到达,则需要考虑是否触发容错机制,例如重新触发子任务或标记任务为异常状态。

需要注意的是,使用子母单和日志表来实现消息的绝对顺序一致性需要综合考虑系统的性能、可扩展性和数据顺序一致性等因素。在具体的实现中,可能还需要考虑并发处理、事务处理和错误处理等问题。

具体的实现方式可以根据具体的业务需求和系统架构来确定。建议在实施之前进行充分的设计和测试,以确保满足业务需求和数据顺序一致性的要求。


结语:

        MQ来实现顺序消息,哪些环节会导致消息不顺序呢?

                生产端-mq服务-消费端,都有不同场景会导致消息非顺序性

        我将顺序消息这个场景分为三种情况:

                1.  仅仅要求尽可能保证顺序性

                        可以改分区策略,将一组需要顺序的消息投递到同一个分区,消费时如是多线程则再进行一次消息分配,尽可能保证顺序性[如果明知消息会有一定间隔性这一步可省略]。

                        这是一种相对乐观的解法

                2. 业务要求消息最终一致性

                        即:业务上需要的是ABC三个消息按照“顺序”消费最终达到S状态

                        首先同样如上投递到同一个分区
                        其次在消费业务上做一定手段,允许ABC三个消息非顺序消费,业务处理好做到“虚假”顺序消费,从而达到最终一致。

                        不过这里需要注意的是业务能否接受这种情况或者说是否符合“虚假”顺序消费的定义(即:不需要严格意义上的顺序消费)

                3. ABC需要严格的全局顺序消费,必须先消费A然后B其次C
                        首先同样如上投递到同一个分区
                        然后在消费端做本地消息日志(上述子母单即是这种方案),记录同一组中的某个阶段消息是否到达,如全部到达再进行顺序消费(这里的触发时机看起来是只有消费后触发,实际上可以加兜底机制,定期去拉N分钟前已经全部到达但是未处理的消息,拉出来去做补偿处理)

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值