rocketmq 顺序消息原理与实战

消费者pull和push

pull 为主动从broker获取消息
Push为broker主动推送消息个consumer 实时性更高,但流量要自己控制
PullBatchSize,代表的是每次从broker的一个队列上拉取的最大消息数。
consumeThreadMax 和 consumeThreadMin 代表消费者pull消息时需要的线程最大和最小数量

广播模式和集群模式

广播把消息发送给订阅这个主题的所有消费者
广播消息不支持消息重试

集群是消息只要有一个消费者消费后变算为消费成功
顺序消息必须为集群模式

顺序消息:

Rocketmq全局顺序消息和局部顺序
全局顺序:一个Topic内所有的消息按照先进先出的顺序进行发布和消费。
部分顺序:一个部分内所有的消息按照先进先出的顺序进行发布和消费。

三个阶段保证消息顺序:
生产顺序性:单一的生产者 并且 串行发送消息
存储时保持和发送的顺序一致
消费时保持和存储的顺序一致

关于重试:

顺序消息可以设置最大重试次数,若不设置则可以认为是无限次
若设置,则达到最大重试次数时消息会变为已消费,会执行后序消息,可能无法保证消息的顺序性,所以要做好顺序验证

顺序消息的重试间隔为固定时间
无序消息的重试时间为阶梯时间

重试次数可通过maxReconsumeTimes 参数进行设置

广播消息不可重试

全局顺序

生产者
创建topic时只创建一个queue,所有的消息都保存在同一个broker里就可以保证顺序
或者选择其中一个队列也可以
生产者就和普通的没区别

producer.send(message);

消费者

@PostConstruct
public void init{
    consumer = new DefaultMQPushConsumer("group");
    consumer.setNamesrvAddr("1270.0.1:9876");
    consumer.setMessageModel(MessageModel.BROADCASTING);
    consumer.setPullInterval(2000);
    consumer.setPullBatchSize(100);
	// 顺序消息设置为1,多个其他的会被空置
    consumer.setConsumeThreadMin(1);

    try {
        consumer.subscribe("topic", "tag");
    } catch (MQClientException e) {
        throw new RuntimeException(e);

    }
    consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -> {
        if (CollectionUtils.isEmpty(msgs)) {
            return ConsumeOrderlyStatus.SUCCESS;
        }
        for (MessageExt msg : msgs) {
            try {
                // 处理message消息
            } catch (Exception e) {
                log.info("Consumer message failed", e);
                throw new RuntimeException(e);
            }
        }
        return ConsumeOrderlyStatus.SUCCESS;
    });
    try {
        consumer.start();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

局部顺序

假设场景,一个订单的不同操作需要保证顺序,比如订单生成->支付->完成
此时方法中arg参数传订单号即可,保证需要顺序的消息有一个统一的标识可以进入到同一个队列中
顺序消息的逻辑就是通过统一标识的hashcode和队列数量size进行取余操作
所以顺序消息有个前提是这个topic的队列数量不可随意修改(倍数可以),否则顺序消息会出现异常(可提前设置此topic的队列数量为最大值16)

生产者

public void sendMsg(MessageInfo info,Object arg){
    String json = JSON.toJSONString(info);
    Message message = new Message("messageType", json.getBytes());
    try {
        producer.send(message, new MessageQueueSelector() {
            @Override
            public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
                int value = arg.hashCode() % list.size();
                if (value < 0) {
                    value = Math.abs(value);
                }
                return list.get(value);
            }
        }, arg);
    } catch (Exception e) {
        throw new RuntimeException(e);
    } 
}

消费者
同全局顺序消费

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荼白z

感谢老板请我喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值