源码地址
springboot2教程系列
rocketmq安装
RocketMQ消息类型
普通消息
普通消息也叫做无序消息,简单来说就是没有顺序的消息,producer 只管发送消息,consumer 只管接收消息,至于消息和消息之间的顺序并没有保证,可能先发送的消息先消费,也可能先发送的消息后消费。
因为不需要保证消息的顺序,所以消息可以大规模并发地发送和消费,吞吐量很高,适合大部分场景。
有序消息
有序消息就是按照一定的先后顺序的消息类型。
事务消息
- 事务消息:MQ 提供类似 X/Open XA 的分布事务功能,通过 MQ 事务消息能达到分布式事务的最终一致。
- 半消息:暂不能投递的消息,发送方已经将消息成功发送到了 MQ 服务端,但是服务端未收到生产者对该消息的二次确认,此时该消息被标记成“暂不能投递”状态,处于该种状态下的消息即半消息。
- 消息回查:由于网络闪断、生产者应用重启等原因,导致某条事务消息的二次确认丢失,MQ 服务端通过扫描发现某条消息长期处于“半消息”时,需要主动向消息生产者询问该消息的最终状态(Commit 或是 Rollback),该过程即消息回查。
实现原理
- 发送方向 MQ 服务端发送消息。
- MQ Server 将消息持久化成功之后,向发送方 ACK 确认消息已经发送成功,此时消息为半消息。
- 发送方开始执行本地事务逻辑。
- 发送方根据本地事务执行结果向 MQ Server 提交二次确认(Commit 或是 Rollback),MQ Server 收到 Commit 状态则将半消息标记为可投递,订阅方最终将收到该消息;MQ Server 收到 Rollback 状态则删除半消息,订阅方将不会接受该消息。
- 在断网或者是应用重启的特殊情况下,上述步骤4提交的二次确认最终未到达 MQ Server,经过固定时间后 MQ Server 将对该消息发起消息回查。
- 发送方收到消息回查后,需要检查对应消息的本地事务执行的最终结果。
- 发送方根据检查得到的本地事务的最终状态再次提交二次确认,MQ Server 仍按照步骤4对半消息进行操作。
Springboot2集成
引入依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
生产者
application.yml配置
server:
port: 9666
rocketmq.name-server: 10.10.2.137:9876
rocketmq.producer.group: my-group
普通消息
同步发送
指消息发送方发出数据后,会在收到接收方发回响应之后才发下一个数据包的通讯方式。
rocketMQTemplate.convertAndSend(topic, msg);
异步发送
指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。MQ 的异步发送,需要用户实现异步发送回调接口(SendCallback),在执行消息的异步发送时,应用不需要等待服务器响应即可直接返回,通过回调接口接收务器响应,并对服务器的响应结果进行处理。
rocketMQTemplate.asyncSend(topic, msg,new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("传输成功");
log.info(JSON.toJSONString(sendResult));
}
@Override
public void onException(Throwable e) {
log.error("传输失败", e);
}
});
单向(Oneway)发送
特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。此方式发送消息的过程耗时非常短,一般在微秒级别。
应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。
rocketMQTemplate.sendOneWay(topic, msg);
延时消息
RocketMQ
目前只支持固定精度的定时消息。
- 延迟级别(18个等级)
1到18分别对应1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
Message message = MessageBuilder.withPayload(msg).build();
rocketMQTemplate.syncSend(topic, message,1000,2);//表示延时5秒
顺序消息
asyncSendOrderly(String destination, Object payload, String hashKey, SendCallback sendCallback)
通过指定hashkey实现顺序消费,同步的hashkey会按顺序消费
消费者设置
@RocketMQMessageListener(topic = "test-topic-1", consumerGroup = "group2",consumeMode = ConsumeMode.ORDERLY)
事务消息
消息回调
@RocketMQTransactionListener(txProducerGroup="group1")
@Slf4j
public class TransactionListener implements RocketMQLocalTransactionListener {
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// local transaction process, return bollback, commit or unknown
log.info("executeLocalTransaction:"+JSON.toJSONString(msg));
return RocketMQLocalTransactionState.UNKNOWN;
}
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
log.info("checkLocalTransaction:"+JSON.toJSONString(msg));
return RocketMQLocalTransactionState.UNKNOWN;
}
}
executeLocalTransaction
方法中执行本地事务逻辑。
checkLocalTransaction
方法执行事务回查逻辑。
- UNKNOW状态:表示事务消息未确定,可能是业务方执行本地事务逻辑时间耗时过长或者网络原因等引起的,该状态会导致broker对事务消息进行回查,默认回查总次数是15次,第一次回查间隔时间是6s,后续每次间隔60s,
- ROLLBACK状态,该状态表示该事务消息被回滚,因为本地事务逻辑执行失败导致
- COMMIT状态,表示事务消息被提交,会被正确分发给消费者。
消息发送
public String sendTx(@PathVariable String topic,@PathVariable String msg) throws InterruptedException {
Message message = MessageBuilder.withPayload(msg).build();
System.out.println(Thread.currentThread().getName());
TransactionSendResult result = rocketMQTemplate.sendMessageInTransaction("group1", topic, message,"test");
System.out.println(result.getTransactionId());
return "sendtx";
}
消费者
application.yml配置
server:
port: 9777
rocketmq.name-server: 10.10.2.137:9876
添加监听
@Slf4j
@Service
@RocketMQMessageListener(topic = "test-topic-1", consumerGroup = "group2",
consumeMode = ConsumeMode.CONCURRENTLY,messageModel=MessageModel.CLUSTERING)
public class ConsumerListener implements RocketMQListener<String> {
public void onMessage(String message) {
log.info("received message: {}", message);
// throw new IllegalStateException();
}
}
- 消费模式:有序消费和并发消费。
有序消费模式是按照消息的顺序进行消费,并发消费的消费速度要比有序消费更快。 - 消息模式: Clustering 和Broadcasting
CLUSTERING:同组里的每个Consumer 只消费所订阅消息的一部分内容。
BROADCASTING:同组里的每个Consumer 消费所订阅消息的全部内容
消息过滤
通过在消费者设置selectorType
,selectorExpression
@RocketMQMessageListener(topic = "test-topic-1", consumerGroup = "group2",
selectorExpression="tag1",selectorType = SelectorType.TAG)
消费者中会消费tag为tag1的消息。
生产者发送指定tag消息方式如下
rocketMQTemplate.convertAndSend(topic+":tag1", msg+":tag1");