应用场景
异步通信、解耦服务或者流量削峰
使用
依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
配置消息队列
在application.properties中配置
rocketmq.name-server=127.0.0.1
rocketmq.producer.group=test
rocketmq.producer.send-message-timeout=30000
rocketmq.test.topic=topicfortest
rocketmq.test.consumer=topicfortestconsumer
编写相应的配置类以及注册rocketmqtemplate的bean
@Configuration
@Data
public class RocketMQConfiguration {
@Value("${rocketmq.name-server}")
private String nameServer;
@Value("${rocketmq.producer.group}")
private String producerGroup;
@Value("${rocketmq.test.topic}")
private String topic;
@Value("${rocketmq.test.tag1}")
private String tag1;
@Value("${rocketmq.test.tag2}")
private String tag2;
@Value("${rocketmq.test.consumer}")
private String consumer;
@Bean
public RocketMQTemplate rocketMQTemplate() {
var producer = new DefaultMQProducer(producerGroup);
producer.setNamesrvAddr(nameServer);
var rocketMQTemplate = new RocketMQTemplate();
rocketMQTemplate.setProducer(producer);
return rocketMQTemplate;
}
}
编写发送消息和生产消息的逻辑
@Service
@AllArgsConstructor
@Slf4j
public class RocketMQService {
private final RocketMQTemplate rocketMQTemplate;
private final RocketMQConfiguration rocketMQConfiguration;
/**
* 发送消息
* @param message 消息
* @return 响应
*/
public SendResult sendMessage(String message) {
DefaultMQProducer producer = rocketMQTemplate.getProducer();
Message msg = new Message(rocketMQConfiguration.getTopic(), rocketMQConfiguration.getTag1(), message.getBytes());
SendResult res = null;
try {
res = producer.send(msg);
} catch (Exception e) {
log.error("发送消息失败:{}", e.getMessage(), e);
}
return res;
}
public void processMessage(String o) {
log.info("收到消息:{}", o);
}
}
定义消费者类
@Service
@RocketMQMessageListener(topic = "${rocketmq.test.topic}", consumerGroup = "${rocketmq.test.consumer}")
@Slf4j
public class RocketMQConsumer implements RocketMQListener<Object> {
@Resource
private RocketMQService rocketMQService;
@Override
public void onMessage(Object o) {
if(o instanceof String){
rocketMQService.processMessage((String) o);
}
}
}
定义接口
@ApiOperation("rocketmq发送一条数据")
@GetMapping("sendMessage")
public ResponseResult<SendResult> testError(@RequestParam String msg){
return ResponseResult.success(rocketMQService.sendMessage(msg));
}
发起请求
执行结果
接口的返回
{
"code": 200,
"message": "响应成功",
"data": {
"sendStatus": "SEND_OK",
"msgId": "7F000001394C2437C6DC5B618C250000",
"messageQueue": {
"topic": "testForTopic",
"brokerName": "broker-1",
"queueId": 0
},
"queueOffset": 0,
"transactionId": null,
"offsetMsgId": "644CA01B000010D50000000053EF424E",
"regionId": "DefaultRegion",
"traceOn": true
}
}
控制台输出的日志
问题
rocketmq的消息会不会丢失?
RocketMQ 设计时就考虑到了高可用性和消息的可靠性,并提供了多种机制来保证消息不会丢失。以下是一些关键机制:
-
消息持久化:RocketMQ 将消息存储在磁盘上,而不仅仅是内存中,确保即使系统崩溃也能恢复丢失的消息。Broker 会将消息写入 CommitLog 文件中,这些文件是持久化存储消息的核心部分。
-
消息确认机制(Producer端):
- 同步发送:生产者发送消息后会等待 Broker 的确认,确保消息已成功存储。
- 异步发送:生产者可以在回调中接收到 Broker 的确认信息,根据返回结果选择是否重试。
- 单向发送:不关注消息是否发送成功,因此不保证消息的可靠性。
-
Broker 高可用机制:通过 Master-Slave 架构和同步或异步复制模式,防止因 Broker 故障导致的消息丢失。
-
消费端的可靠性:包括消费确认、消费位点管理和消息消费重试机制,确保消费者能够正确处理消息,避免重复消费或漏消费。
-
事务消息:提供两阶段提交机制,确保分布式环境中消息发送与业务操作的一致性。
-
消息幂等性:生产者可以通过设置唯一键来保证消息的幂等性,即在网络问题或重试过程中,消息只会被处理一次。
rocketmq的消息是否有序?
场景:
rocketmq的消息是否有序?比如说,我的应用场景是,让生产端处理10条数据,每条数据处理完成后会把结果通过rocketmq发送给消费端。并且当生产端处理完所有数据后,还会额外发送一条表示已完成所有数据处理的消息。所以生产端处理10条数据后,实际上会发送11条消息。
请问这11条消息是否会按顺序消费?
回答:
RocketMQ 支持分区顺序消息,即在同一个消息队列(Message Queue)中的消息是严格有序的。但是,由于一个主题(Topic)可能包含多个消息队列,因此如果消息分布在不同的队列上,则无法保证全局顺序。创建一个只包含一个消息队列的主题。这样,所有发送到该主题的消息都会进入同一个队列,从而保证它们的顺序。
另外要保证生产端按顺序发送消息,然后消费端使用单线程消费模式处理消息。
设置消费组为顺序消费模式
配置 consumeMode:在 @RocketMQMessageListener 注解中设置 consumeMode = ConsumeMode.ORDERLY。
关闭并发线程:通过 consumer 参数强制设置并发线程数为 1
@RocketMQMessageListener(
topic = "${rocketmq.test.topic}",
consumerGroup = "${rocketmq.test.consumer}",
consumeMode = ConsumeMode.ORDERLY,
consumeThreadMax = 1
)
顺序消费
consumeMode = ConsumeMode.ORDERLY,
consumeThreadMax = 1
并发消费
consumeMode = ConsumeMode.CONCURRENTLY,
consumeThreadMax = 64
并发消费结果图
rocketmq的消息能不能多节点消费
可以多节点消费,同时单节点也可以设置并发消费。
在 @RocketMQMessageListener 注解中设置 consumeMode = ConsumeMode.CONCURRENTLY。
关闭并发线程:通过 consumer 参数强制设置并发线程数为 64
使用rocketmq的注意事项
幂等性设计
需要消费端自己处理可能的重复消息。
- 通过数据库的唯一键约束避免重复消费
- 使用分布式锁或redis缓存来控制并发访问