首先说下消息重复发送的原因:
- 消息异常重复发送
- 消费消息抛出异常
- 重平衡
- 清理长时间消费的消息
- 消费者提交
offset
失败- 主从同步
offset
失败- 服务端持久化
offset
失败
在说正面的失败原因前,我们先看下rocketmq
前提的基础知识
RocketMQ
发送消费消息的基本原理(按照FIFO
算法)
- 生产者发送消息,
- 通过负载均衡算法,选择发送给一个
Broker
下面的topic
队列QUEUE
,- 当中首先跟这个队列建立连接,随后把消息发送给此
QUEUE
- 若消费者消费到此
queue
,消息就被消费啦!~
简单说明下:
-
Broker
: 服务端 -
Topic
:一类消息集合的名字 -
Queue
:就是Topic
集合中的成员(队列),存储消息的===> 咋理解呢?就是大头兵,真正干活的,存消息的
上面的基本原理是建立在正常的情况下,但是(哈哈,最怕但是了~),就是我们本文的核心了!异常情况下呢?
一、消息异常重复发送
比如消息发送超时,响应超时,中途中断等等
这个时候我们的RocketMQ
为了保证消息成功发送,就会进行消息发送的重试操作,一般会重试两次
//重试次数默认两次,三次只对同步调用生效
private int retryTimesWhenSendFailed=2;
你可能会问?怎么进行重试操作呢?
选择另一台机器的
QUEUE
来发送就行啦!这个重试操作:好处就是很好保证消息的发送成功,但是会带来的问题就是消息重复发送
eg:
mq
第一次发送消息,但是当时网速很慢,恰好过了超时时间,到达服务端,服务端接受并处理了,
但是发送端因为超时机制,又再次发送消息,这就导致了消息相同重复问题
(好家伙,有没有像计算机握手画面~哈哈)
二、消费消息抛出异常
我们在使用
RocketMQ
时,当我们处于并发消费消息的模式下,我们就需要:
- 实现接口:
MessageListenerConcurrencyly
(目的:处理消息)- 其次:
- 当消费者
get
到msg
后,- 就会调用
MessageListenerConcurrencyly
的实现,- 传入需要消费的消息集合
msgs
(这玩意是核心)
上面代码,当消息出现异常的时候:
status=null
,我们会看到status
被设置为RECONSUME_LATER
(稍后重新消费)
所以一旦抛出异常,那么消息就可以被重复消费!重复消费!!重复消费!!!(重要的说三遍!!!)
你可能会说?这不是正常的操作嘛!抛出异常,消息都没消费成功,不重复消费咋整??
嗯哼,你提问的这个是对的哈,但是(哈哈,有转折了哈!)
我们往前捋一捋,我们消费时,服务端队列我们传入的是整个集合(关键点就在这!!!)
这意味着什么意思呢?
当然使整个消息集合都重新消费(有没有反应过来??没有?我们继续往下看啊!~)
消息处理之后,不论是成功还是异常,都需要对结果进行处理,代码如下: