摘要: 原创出处 http://www.iocoder.cn/RocketMQ/message-send-and-receive/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文主要基于 RocketMQ 4.0.x 正式版
- 《Dubbo 实现原理与源码解析 —— 精品合集》
- 《Netty 实现原理与源码解析 —— 精品合集》
- 《Spring 实现原理与源码解析 —— 精品合集》
- 《MyBatis 实现原理与源码解析 —— 精品合集》
- 《Spring MVC 实现原理与源码解析 —— 精品合集》
- 《数据库实体设计合集》
- 《Java 面试题 —— 精品合集》
- 《Java 学习指南 —— 精品合集》
1、概述
Producer
发送消息。主要是同步发送消息源码,涉及到 异步/Oneway发送消息,事务消息会跳过。Broker
接收消息。(存储消息在《RocketMQ 源码分析 —— Message 存储》解析)
2、Producer 发送消息
DefaultMQProducer#send(Message)
1: @Override
2: public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
3: return this.defaultMQProducerImpl.send(msg);
4: }
- 说明:发送同步消息,
DefaultMQProducer#send(Message)
对DefaultMQProducerImpl#send(Message)
进行封装。
DefaultMQProducerImpl#sendDefaultImpl()
1: public SendResult send(Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
2: return send(msg, this.defaultMQProducer.getSendMsgTimeout());
3: }
4:
5: public SendResult send(Message msg, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
6: return this.sendDefaultImpl(msg, CommunicationMode.SYNC, null, timeout);
7: }
8:
9: private SendResult sendDefaultImpl(//
10: Message msg, //
11: final CommunicationMode communicationMode, //
12: final SendCallback sendCallback, //
13: final long timeout//
14: ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
15: // 校验 Producer 处于运行状态
16: this.makeSureStateOK();
17: // 校验消息格式
18: Validators.checkMessage(msg, this.defaultMQProducer);
19: //
20: final long invokeID = random.nextLong(); // 调用编号;用于下面打印日志,标记为同一次发送消息
21: long beginTimestampFirst = System.currentTimeMillis();
22: long beginTimestampPrev = beginTimestampFirst;
23: long endTimestamp = beginTimestampFirst;
24: // 获取 Topic路由信息
25: TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
26: if (topicPublishInfo != null && topicPublishInfo.ok()) {
27: MessageQueue mq = null; // 最后选择消息要发送到的队列
28: Exception exception = null;
29: SendResult sendResult = null; // 最后一次发送结果
30: int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1; // 同步多次调用
31: int times = 0; // 第几次发送
32: String[] brokersSent = new String[timesTotal]; // 存储每次发送消息选择的broker名
33: // 循环调用发送消息,直到成功
34: for (; times < timesTotal; times++) {
35: String lastBrokerName = null == mq ? null : mq.getBrokerName();
36: MessageQueue tmpmq = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName); // 选择消息要发送到的队列
37: if (tmpmq != null) {
38: mq = tmpmq;
39: brokersSent[times] = mq.getBrokerName();
40: try {
41: beginTimestampPrev = System.currentTimeMillis();
42: // 调用发送消息核心方法
43: sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout);
44: endTimestamp = System.currentTimeMillis();
45: // 更新Broker可用性信息
46: this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
47: switch (communicationMode) {
48: case ASYNC:
49: return null;
50: case ONEWAY:
51: return null;
52: case SYNC:
53: if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
54: if (this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) { // 同步发送成功但存储有问题时 && 配置存储异常时重新发送开关 时,进行重试
55: continue;
56: }
57: }
58: return sendResult;
59: default:
60: break;
61: }
62: } catch (RemotingException e) { // 打印异常,更新Broker可用性信息,更新继续循环
63: endTimestamp = System.currentTimeMillis();
64: this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
65: log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
66: log.warn(msg.toString());
67: exception = e;
68: continue;
69: } catch (MQClientException e) { // 打印异常,更新Broker可用性信息,继续循环
70: endTimestamp = System.currentTimeMillis();
71: this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
72: log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
73: log.warn(msg.toString());
74: exception = e;
75: continue;
76: } catch (MQBrokerException e) { // 打印异常,更新Broker可用性信息,部分情况下的异常,直接返回,结束循环
77: endTimestamp = System.currentTimeMillis();
78: this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true);
79: log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
80: log.warn(msg.toString());
81: exception = e;
82: switch (e.getResponseCode()) {
83: // 如下异常continue,进行发送消息重试
84: case ResponseCode.TOPIC_NOT_EXIST:
85: case ResponseCode.SERVICE_NOT_AVAILABLE:
86: case ResponseCode.SYSTEM_ERROR:
87: case ResponseCode.NO_PERMISSION:
88: case ResponseCode.NO_BUYER_ID:
89: case ResponseCode.NOT_IN_CURRENT_UNIT:
90: continue;
91: // 如果有发送结果,进行返回,否则,抛出异常;
92: default:
93: if (sendResult != null) {
94: return sendResult;
95: }
96: throw e;
97: }
98: } catch (InterruptedException e) {
99: endTimestamp = System.currentTimeMillis();
100: this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
101: log.warn(String.format("sendKernelImpl exception, throw exception, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e);
102: log.warn(msg.toString());
103: throw e;
104: }
105: } else {
106: break;
107: }
108: }
109: // 返回发送结果
110: if (sendResult != null) {
111: return sendResult;
112: }
113: // 根据不同情况,抛出不同的异常
114: String info = String.format("Send [%d] times, still failed, cost [%d]ms, Topic: %s, BrokersSent: %s", times, System.currentTimeMillis() - beginTimestampFirst,
115: msg.getTopic(), Arrays.toString(brokersSent)) + FAQUrl.suggestTodo(FAQUrl.SEND_MSG_FAILED);
116: MQClientException mqClientException = new MQClientException(info, exception);
117: if (exception instanceof MQBrokerException) {
118: mqClientException.setResponseCode(((MQBroker