RocketMQ简介

目录

MQ介绍

MQ的优点和缺点

各种MQ产品的比较

消息发送者步骤分析

消息消费者步骤分析

顺序消息

延时消息

事务消息

1)事务消息发送及提交

2)事务补偿

3)事务消息状态

使用限制

重试队列

重试配置

怎么保证消息消费的时候0丢失?

怎么解决重试幂等性问题?

死信队列

死信队列具有以下特性:


MQ介绍

1.1 为什么要用MQ

消息队列是一种“先进先出”的数据结构

消息队列是一种“先进先出”的数据结构其应用场景主要包含以下3个方面

  • 应用解耦

  • 流量削峰

  • 数据分发

1、 系统的耦合性越高,容错性就越低。以电商应用为例,用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障或者因为升级等原因暂时不可用,都会造成下单操作异常,影响用户使用体验。

 

       使用消息队列解耦合,系统的耦合性就会降低了。比如物流系统发生故障,需要几分钟才能来修复,在这段时间内,物流系统要处理的数据被缓存到消息队列中,用户的下单操作正常完成。当物流系统恢复后,补充处理存在消息队列中的订单消息即可,终端系统感知不到物流系统发生过几分钟故障。

2、应用系统如果遇到系统请求流量的瞬间猛增,有可能会将系统压垮。有了消息队列可以将大量请求缓存起来,分散到很长一段时间处理,这样可以大大提到系统的稳定性和用户体验。

 一般情况,为了保证系统的稳定性,如果系统负载超过阈值,就会阻止用户请求,这会影响用户体验,而如果使用消息队列将请求缓存起来,等待系统处理完毕后通知用户下单完毕,这样总比不能下单体验要好。

3、通过消息队列可以让数据在多个系统之间进行流通。数据的产生方不需要关心谁来使用数据,只需要将数据发送到消息队列,数据使用方直接在消息队列中直接获取数据即可

 使用mq

MQ的优点和缺点

优点:解耦、削峰、数据分发

缺点包含以下几点:

  • 系统可用性降低

    系统引入的外部依赖越多,系统稳定性越差。一旦MQ宕机,就会对业务造成影响。

    如何保证MQ的高可用?

答:使用 同步双写 集群模式 这就保证了消息的 安全性、不易丢失,但是会 损耗大概百分之十的性能

  • 系统复杂度提高

    MQ的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过MQ进行异步调用。

    如何保证消息没有被重复消费?怎么处理消息丢失情况?那么保证消息传递的顺序性?

答:

发送消息的时候指定 队列选择器,把要 保证顺序的消息 发送到 同一个队列 中,利用一个 队列天然有序的特性 来保证消息的有序性消费者使用 orderly 的监听器

总结: 顺序消息 就是在生产者 指定MessageQueueSelector消费者 去指定 MessageListenerOrderly

  • 一致性问题

    A系统处理完业务,通过MQ给B、C、D三个系统发消息数据,如果B系统、C系统处理成功,D系统处理失败。

    如何保证消息数据处理的一致性?

答:将处理过的消息存到数据库中的trade_mq_consumer_log 表中,我们拿到一条消息 不是拿来立马就进行消费 而是先判断这个消息是否被处理过,如果被处理过 就无须再次处理,否则 就会出现幂等性问题 说白了 避免消息重复消费。(使用数据库的 乐观锁 更改消息的状态 避免并发问题)

各种MQ产品的比较

消息发送者步骤分析

1.创建消息生产者producer,并制定生产者组名
2.指定Nameserver地址
3.启动producer
4.创建消息对象,指定主题Topic、Tag和消息体
5.发送消息
6.关闭生产者producer

消息消费者步骤分析

1.创建消费者Consumer,制定消费者组名
2.指定Nameserver地址
3.订阅主题Topic和Tag
4.设置回调函数,处理消息
5.启动消费者consumer

顺序消息

        消息有序指的是可以按照消息的发送 顺序来消费(FIFO)。RocketMQ可以严格的保证消息有序,可以分为分区有序或者全局有序。

        顺序消费的原理解析,在默认的情况下消息发送会采取Round Robin轮询方式把消息发送到不同的queue(分区队列);而消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序。当发送和消费参与的queue只有一个,则是全局有序;如果多个queue参与,则为分区有序,即相对每个queue,消息都是有序的。

延时消息

 RocketMq并不支持任意时间的延时,需要设置几个固定的延时等级,从1s到2h分别对应着等级1到18  (共18个等级)

事务消息

 流程分析

        事务消息 producer 发送给MQ的消息是带有事务控制的, 发的消息需要生产者一个事务的提交 如果 消息发送给MQ Server 但是没有提交事务 那么这个消息是不能被消费者消费的 ,这种由于生产者没有提交 而导致消费者不可消费的消息 我们称之为 half 消息,half 消息发送完了之后重试 MQ 会给生产者一个反馈 消息已经收到了,然后生产者执行本地的事务,当你把本地事务执行完了之后 生产者再对half消息执行一个 Commit 或者 Rollback , 当做了Commit 操作 ,则消息可以被消费者消费了,如果执行了Rollback ,MQ Server 就会把这个消息删除掉,消费者就接受不到这个消息了,如果在做提交 和 回滚操作时 失败了 或者超时了 这个时候 MQ Server 会对消息做一个回查 就是一个Check Back 通过回调方法检查消息的状态 通过检查状态 再对消息进行 处理(提交或回滚)

其中分为两个流程:正常事务消息的发送及提交、事务消息的补偿流程

1)事务消息发送及提交

(1) 发送消息(half消息)。

(2) 服务端响应消息写入结果。

(3) 根据发送结果执行本地事务(如果写入失败,此时half消息对业务不可见,本地逻辑不执行)。

(4) 根据本地事务状态执行Commit或者Rollback(Commit操作生成消息索引,消息对消费者可见)

2)事务补偿

(1) 对没有Commit/Rollback的事务消息(pending状态的消息),从服务端发起一次“回查”

(2) Producer收到回查消息,检查回查消息对应的本地事务的状态

(3) 根据本地事务状态,重新Commit或者Rollback

其中,补偿阶段用于解决消息Commit或者Rollback发生超时或者失败的情况。

3)事务消息状态

事务消息共有三种状态,提交状态、回滚状态、中间状态:

  • TransactionStatus.CommitTransaction: 提交事务,它允许消费者消费此消息。

  • TransactionStatus.RollbackTransaction: 回滚事务,它代表该消息将被删除,不允许被消费。

  • TransactionStatus.Unknown: 中间状态,它代表需要检查消息队列来确定状态。

使用限制

  1. 事务消息 不支持 延时消息 和 批量消息。

  2. 为了避免单个消息被检查太多次而导致半队列消息累积,我们默认将单个消息的检查次数限制为 15 次,但是用户可以通过 Broker 配置文件的 transactionCheckMax参数来修改此限制。如果已经检查某条消息超过 N 次的话( N = transactionCheckMax ) 则 Broker 将丢弃此消息,并在默认情况下同时打印错误日志。用户可以通过重写 AbstractTransactionCheckListener 类来修改这个行为。

  3. 事务消息将在 Broker 配置文件中的参数 transactionMsgTimeout 这样的特定时间长度之后被检查。当发送事务消息时,用户还可以通过设置用户属性 CHECK_IMMUNITY_TIME_IN_SECONDS 来改变这个限制,该参数优先于 transactionMsgTimeout 参数。

  4. 事务性消息可能不止一次被检查或消费。

  5. 提交给用户的目标主题消息可能会失败,目前这依日志的记录而定。它的高可用性通过 RocketMQ 本身的高可用性机制来保证,如果希望确保事务消息不丢失、并且事务完整性得到保证,建议使用同步的双重写入机制。

  6. 事务消息的生产者 ID 不能与其他类型消息的生产者 ID 共享。与其他类型的消息不同,事务消息允许反向查询、MQ服务器能通过它们的生产者 ID 查询到消费者。

重试队列

RocketMQ消费端默认有重试机制,消费端重试分为两种情况

  1. 异常重试:由于Consumer端逻辑出现了异常,导致返回了RECONSUME_LATER状态,那么Broker就会在一段时间后尝试重试。

  2. 超时重试:如果Consumer端处理时间过长,或者由于某些原因线程挂起,导致迟迟没有返回消费状态,Broker就会认为Consumer消费超时,此时会发起超时重试。

设置重试时间与次数:

可在broker.conf文件中配置Consumer端的重试次数和重试时间间隔

第几次重试与上次重试的间隔时间第几次重试与上次重试的间隔时间
110 秒97 分钟
230 秒108 分钟
31 分钟119 分钟
42 分钟1210 分钟
53 分钟1320 分钟
64 分钟1430 分钟
75 分钟151 小时
86 分钟162 小时

如果消息重试 16 次后仍然失败,消息将不再投递。如果严格按照上述重试时间间隔计算,某条消息在一直消费失败的前提下,将会在接下来的 4 小时 46 分钟之内进行 16 次重试,超过这个时间范围消息将不再重试投递。

注意: 一条消息无论重试多少次,这些重试消息的 Message ID 不会改变。

重试配置

集群消费方式下,消息消费失败后期望消息重试,需要在消息监听器接口的实现中明确进行配置(三种方式任选一种):

  • 返回 RECONSUME_LATER (推荐)

  • 返回 Null

  • 抛出异常

注意1:只有在消息模式为MessageModel.CLUSTERING集群模式时,Broker才会自动进行重试,广播消息是不会重试的。

注意2:由于MQ的重试机制,难免会引起消息的重复消费问题。比如一个ConsumerGroup中有两个,Consumer1和Consumer2,以集群方式消费。假设一条消息发往ConsumerGroup,由Consumer1消费,但是由于Consumer1消费过慢导致超时,如果Broker将消息发送给Consumer2去消费,这样就产生了重复消费问题。因此,使用MQ时应该对一些关键消息进行幂等去重的处理。

怎么保证消息消费的时候0丢失?

答:Rocketmq默认就有重试机制,如果第一次消费的时候,broker收到的回应是(ConsumeConcurrentlyStatus.RECONSUME_LATER),那么这条消息不会丢失,会进入重试队列,重试的次数与重试的时间可以配置,如果重试的次数超过配置的次数,那么这条消息没有丢失,但是放入死信队列

怎么解决重试幂等性问题?

答:如果重试很有可能出现幂等性问题,需要业务逻辑做配合,比如可以先判断数据库的状态,然后根据数据库的状态,做对应的处理

其实 就是 占坑 思想 , 比如 setnx 多个消费者 只有第一个消费者 占坑成功 可以消费

死信队列

当一条消息初次消费失败,消息队列 RocketMQ 会自动进行消息重试,达到最大重试次数后,若消费依然失败,则表明消费者在正常情况下无法正确地消费该消息。此时,消息队列 RocketMQ 不会立刻将消息丢弃,而是将其发送到该消费者对应的特殊队列中。

在消息队列 RocketMQ 版中,这种正常情况下无法被消费的消息称为死信消息(Dead-Letter Message),存储死信消息的特殊队列称为死信队列(Dead-Letter Queue)。


死信消息具有以下特性:
1:不会再被之前的消费者正常消费。
2:有效期与正常消息相同,均为 3 天,3 天后会被自动删除。因此,请在死信消息产生后的 3 天内及时处理。


死信队列具有以下特性:


1:一个死信队列对应一个 Group ID, 而不是对应单个消费者实例。
2:如果一个 Group ID 未产生死信消息,消息队列 RocketMQ 便不会为其创建相应的死信队列。
3:一个死信队列包含了对应 Group ID 产生的所有死信消息,不论该消息属于哪个 Topic。
4:消息队列 RocketMQ 版控制台提供对死信消息的查询、重发的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值