rocketmq消息队列实践

应用场景

异步通信、解耦服务或者流量削峰

使用

依赖

<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 设计时就考虑到了高可用性和消息的可靠性,并提供了多种机制来保证消息不会丢失。以下是一些关键机制:

  1. 消息持久化:RocketMQ 将消息存储在磁盘上,而不仅仅是内存中,确保即使系统崩溃也能恢复丢失的消息。Broker 会将消息写入 CommitLog 文件中,这些文件是持久化存储消息的核心部分。

  2. 消息确认机制(Producer端)

    • 同步发送:生产者发送消息后会等待 Broker 的确认,确保消息已成功存储。
    • 异步发送:生产者可以在回调中接收到 Broker 的确认信息,根据返回结果选择是否重试。
    • 单向发送:不关注消息是否发送成功,因此不保证消息的可靠性。
  3. Broker 高可用机制:通过 Master-Slave 架构和同步或异步复制模式,防止因 Broker 故障导致的消息丢失。

  4. 消费端的可靠性:包括消费确认、消费位点管理和消息消费重试机制,确保消费者能够正确处理消息,避免重复消费或漏消费。

  5. 事务消息:提供两阶段提交机制,确保分布式环境中消息发送与业务操作的一致性。

  6. 消息幂等性:生产者可以通过设置唯一键来保证消息的幂等性,即在网络问题或重试过程中,消息只会被处理一次。

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缓存来控制并发访问
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值