MQ-如何保证消息不丢不重

MQ作为一个消息中间件,很多公司在生产中选择使用它,那么它的可靠性就很重要了,因此如何保证消息不丢不重就是一个需要考虑的问题,本文就是对此问题进行一个分析。下边是mq的基本流程图。

Created with Raphaël 2.3.0 前置服务生产消息 消息中间件存储 后续服务消费消息

一、如何保证消息不丢

首先一个MQ的完成,总共分为三个阶段,分别是生产阶段、存储阶段、消费阶段,所以只要保证这三个阶段消息不丢就可以。

1、生产阶段

在消息生产的过程中,其实本质上就是将消息远程提交给mq服务(broker)的过程,本质上和接口的调用没有什么差别,因此只要保证接收到broker返回的ack确认响应即可。只要处理好返回值和异常,这个阶段是没问题的。
当然,也可以在这一步加一个降级处理已备后患,可以考虑在抓住异常后再发送一个延时任务,等延时任务到了会将此mq重新发送。

2、存储阶段

存储阶段的可靠性一般由中间件来保证,只需要了解它的原理,比如broker会做副本,比如保证一条消息至少同步两个节点再返回ack。

3、消费阶段

在这个阶段,mq在进行处理的时候,如果消费成功会给broker返回消费确认标识。而这个阶段的可靠性保证就可以依靠这个原理,在所有逻辑都执行完成后,再给broker返回消费确认标识,这样就保证了消息的不丢失。

二、如何保证消息不重

解决重复消费的问题,通常只有一个方案,就是让消费端保证幂等性(可以使用相同参数重复执行,并能获得相同结果)。而幂等性的实现方案就可以展开了,在我个人看来大致区分为两个方向。

1、业务幂等

业务幂等指的就是通过类似于刷数据的方案设计接口,就是将某些条件下的修改结果写入一个固定值,比如一个用于将订单状态自动置为完成的消费端就可以这么设计。当然,这个不是一个通用解决方案,它只限于固定的场景。

2、技术幂等

技术幂等的方案就是另一个方向,它主要的考虑是去重,方案就是创建一张消息日志表,这个日志表有消息id和消费状态字段,在生产端发送消息时候创建一个全局唯一id作为消息id放置在报文中发送出去,在消费端进行查询并更改消息状态,如果更改成功在进行业务逻辑处理,如果消费失败再回滚消息状态并让消息重试。而其他的重复消息会在校验消息id这一步就被抛掉。
当然,这个日志表可以通过Mysql设计也可以通过redis等数据库设计,这个完全看各个项目考虑。全局id的设计也有很多种方案,比如Mysql的主键或者Redis的自增,再或者通过UUID或者Snowflake(雪花算法)等等,只要能保证全局唯一,可以自行设计。下面列举了一些常规ID生成方案的优缺点。

方案顺序性重复性存在问题
Mysql自增主键递增不会重复系统复杂度增加,数据库宕机不可用
Redis递增RDB持久化模式下,可能会出现重复系统复杂度增加,Rrdis宕机不可用
UUID无序通过多位随机字符降低重复概率,但仍有极小概率会出现重复一直可用
Snowflake递增不会重复时钟回拨

三、如何处理消息积压

消息积压就需要考虑场景了:

1、突发问题

如果是线上突发问题,就可以考虑临时扩容,增加消费节点,提高消费能力,同时也可以考虑将其他不重要业务场景进行降级处理,将更多的消费资源倾斜给出问题的场景。

2、日常场景

如果不是突发问题而是日常场景,先根据日志和性能检测工具之类的多方面进行评估,先看看是否是设计不合理或者是bug之类的问题导致的性能降低,如果能评估出来就可以将消费端优化处理,再看看是不是消费数量进行了限制,合理的设计mq的并行消费数量,也能对消费性能进行提升。如果前两步都没有问题,单纯的是因为资源不足导致经常积压,就需要申请机器进行水平扩容了。

Ps:这里有一个点需要注意,在使用不同的消息中间件时候,需要考虑到其可能影响到性能的情况,比如在使用kafka时候,kafka的一个topic可以配置多个Partition(分片),发送时候数据会分发给多个分片,但是消费时候一个分片只能被一个消费者消费,这个时候扩容就要考虑到,扩容实例的同时也要同步扩容topic的分片数量,如果两者不等,由于分片是单线程消费,扩容将会没有效果。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摆烂的小趴菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值