RocketMQ消息的发送和消费之其他样例

背景

前文总结了RocketMQ消息的发送和消费之基本样例,发送消息分为发送同步、异步和单向消息,消费消息分为负载均衡模式和广播模式。下面针对于常见的消息类型做一个补充,分为顺序消息、延时消息、批量消息和过滤消息。

1 顺序消息

消息有序指的是可以按照消息的发送顺序来消费(FIFO)。RocketMQ可以严格的保证消息有序,可以分为分区有序或者全局有序

  • 分区有序是指 消费者通过 同一个消费队列收到的消息是有顺序的 ,不同消息队列收到的消息则可能是无顺序的。普通顺序消息在 Broker 重启情况下不会保证消息顺序性 (短暂时间) 。

  • 全局有序是指 消费者收到的 所有消息 均是有顺序的。严格顺序消息 即使在异常情况下也会保证消息的顺序性

顺序消费的原理解析,在默认的情况下消息发送会采取Round Robin轮询方式把消息发送到不同的queue(分区队列);而消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序。当发送和消费参与的queue只有一个,则是全局有序;如果多个queue参与,则为分区有序,即相对每个queue,消息都是有序的。

那么,我们现在使用了 普通顺序模式 ,我们从上面学习知道了在 Producer 生产消息的时候会进行轮询(取决你的负载均衡策略)来向同一主题的不同消息队列发送消息。那么如果此时我有几个消息分别是同一个订单的创建、支付、发货,在轮询的策略下这 三个消息会被发送到不同队列 ,因为在不同的队列此时就无法使用 RocketMQ 带来的队列有序特性来保证消息有序性了。

那么,怎么解决呢?

其实很简单,我们需要处理的仅仅是将同一语义下的消息放入同一个队列(比如这里是同一个订单),那我们就可以使用 Hash取模法 来保证同一个订单在同一个队列中就行了。

下面用订单进行分区有序的示例。一个订单的顺序流程是:创建、付款、推送、完成。订单号相同的消息会被先后发送到同一个队列中,消费时,同一个OrderId获取到的肯定是同一个队列。

1.1 顺序消息生产

/**
* Producer,发送顺序消息
*/
public class Producer {

 public static void main(String[] args) throws Exception {  DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");   producer.setNamesrvAddr("127.0.0.1:9876");   producer.start();   String[] tags = new String[]{
    "TagA", "TagC", "TagD"};   // 订单列表  List<OrderStep> orderList = new Producer().buildOrders();   Date date = new Date();  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  String dateStr = sdf.format(date);  for (int i = 0; i < 10; i++) {  // 加个时间前缀  String body = dateStr + " Hello RocketMQ " + orderList.get(i);  Message msg = new Message("TopicTest", tags[i % tags.length], "KEY" + i, body.getBytes());   SendResult sendResult = producer.send(msg, new MessageQueueSelector() {  @Override  public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {  Long id = (Long) arg; //根据订单id选择发送queue  long index = id % mqs.size();  return mqs.get((int) index);  }  }, orderList.get(i).getOrderId());//订单id   System.out.println(String.format("SendResult status:%s, queueId:%d, body:%s",  sendResult.getSendStatus(),  sendResult.getMessageQueue().getQueueId(),  body));  }   producer.shutdown();  }   /**  * 订单的步骤  */  private static class OrderStep {  private long orderId;  private String desc;   
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值