一、RocketMQ的生产者重试
1.可靠同步模式
原理简解:同步发送是指消息发送方发出数据后,会在收到接收方发回响应之后才发下一个数据包的通讯方式。
应用场景:这种可靠同步方式发送应用场景非常广泛,例如重要通知邮件、报名短信通知、营销短信系统等。
//可靠同步模式send方法 参数CommunicationMode.SYNC 同步
public SendResult send(Message msg, long timeout)
throws MQClientException, RemotingException, MQBrokerException, InterruptedException{
return sendDefaultImpl(msg, CommunicationMode.SYNC, null, timeout);
}
//默认推送broker中的方法 ,其中
private SendResult sendDefaultImpl(Message msg, CommunicationMode communicationMode, SendCallback sendCallback, long timeout)
throws MQClientException, RemotingException, MQBrokerException, InterruptedException
timesTotal = communicationMode != CommunicationMode.SYNC ? 1 : 1 + defaultMQProducer.getRetryTimesWhenSendFailed();
如果是CommunicationMode.SYNC的默认为defaultMQProducer.getRetryTimesWhenSendFailed()。查看源码。retryTimesWhenSendFailed = 2;默认是重试两次。
public DefaultMQProducer(String producerGroup, RPCHook rpcHook, boolean enableMsgTrace, String customizedTraceTopic)
{
log = ClientLogger.getLog();
createTopicKey = "TBW102";
defaultTopicQueueNums = 4;
sendMsgTimeout = 3000;
compressMsgBodyOverHowmuch = 4096;
retryTimesWhenSendFailed = 2;
retryTimesWhenSendAsyncFailed = 2;
retryAnotherBrokerWhenNotStoreOK = false;
maxMessageSize = 4194304;
traceDispatcher = null;
this.producerGroup = producerGroup;
defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook);
if(enableMsgTrace)
try
{
AsyncTraceDispatcher dispatcher = new AsyncTraceDispatcher(producerGroup, org.apache.rocketmq.client.trace.TraceDispatcher.Type.PRODUCE, customizedTraceTopic, rpcHook);
dispatcher.setHostProducer(defaultMQProducerImpl);
traceDispatcher = dispatcher;
defaultMQProducerImpl.registerSendMessageHook(new SendMessageTraceHookImpl(traceDispatcher));
}
catch(Throwable e)
{
log.error("system mqtrace hook init failed ,maybe can't send msg trace data");
}
}
2.可靠异步发送
原理简解:异步发送是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。消息队列 MQ 的异步发送,需要用户实现异步发送回调接口(SendCallback)。消息发送方在发送了一条消息后,不需要等待服务器响应即可返回,进行第二条消息发送。发送方通过回调接口接收服务器响应,并对响应结果进行处理。
应用场景:异步发送一般用于链路耗时较长,对 RT 响应时间较为敏感的业务场景,即发送端不能容忍长时间地等待 Broker 的响应。例如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。
sendDefaultImpl(msg, CommunicationMode.ASYNC, sendCallback, timeout - costTime);
调用默认的sendDefaultImpl方法可以得出默认重试次数为1次。
3.单向发送
原理简解:单向(Oneway)发送特点为发送方只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。此方式发送消息的过程耗时非常短,一般在微秒级别。
应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。
单向发送是不重试的。
二、RocketMQ的消费者重试
实现代码,通过反射机制进行消费
package com.midea.ims.hessianserver.mqlistener;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.neusoft.unieap.core.util.BeanUtil;
/**
* @author : guibr
* @date : 2020/03/09
*/
public class MqMessageListenerImpl implements MessageListenerConcurrently {
private Logger logger = LoggerFactory.getLogger(MqMessageListenerImpl.class);
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
logger.info(Thread.currentThread().getName()
+ " Receive New Messages: " + msgs.size()+";msg:" + msgs);
try{
for(MessageExt msg : msgs){
String jsonText = (String)SerializationUtils.deserialize(msg.getBody());
JSONObject jsonObject = JSON.parseObject(jsonText);
Object bean = BeanUtil.getBean(jsonObject.getString("beanId"));
Method mh = ReflectionUtils.findMethod(bean.getClass(), jsonObject.getString("beanMethod"), new Class[]{String.class});
Object[] params = new Object[]{jsonObject.getString("data")};
ReflectionUtils.invokeMethod(mh, bean, params);
}
}catch (Exception e){
logger.info("call consumeMessage | EXCEPTION :{}",e);
// // 加入重试机制
// if(msgs.get(0).getReconsumeTimes() == 3){
// // 成功
// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
// }else{
// // 重试
// return ConsumeConcurrentlyStatus.RECONSUME_LATER;
// }
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
// 有异常抛出来,不要全捕获了,这样保证不能消费的消息下次重推,每次重新消费间隔:10s,30s,1m,2m,3m
// 如果没有异常会认为都成功消费
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}
ConsumeConcurrentlyStatus.RECONSUME_LATER。消费者默认是重试16次,16次之后就不再重试。
并且重试时间间隔逐步增加1s,5s,10s,30s,1m,2m,3m,4m,5m,6m,7m,8m,9m,10m,20m,30m,1h,2h