六.RocketMQ极简入门-RocketMQ消息批量发送

简介: RocketMQ极简入门-RocketMQ消息批量发送

使用场景

如果消息过多,每次发送消息都和MQ建立连接,无疑是一种性能开销,批量消息可以把消息打包批量发送,批量发送消息能显著提高传递小消息的性能。

批量消息概述

批量发送消息能显著提高传递小消息的性能。限制是这些批量消息应该有相同的topic,而且不能是延时消息。此外,这一批消息的总大小不应超过4MB,如果超过可以有2种处理方案:

1.将消息进行切割成多个小于4M的内容进行发送

2.修改4M的限制改成更大

  • 可以设置Producer的maxMessageSize属性
  • 修改配置文件中的maxMessageSize属性

对于消费者而言Consumer的MessageListenerConcurrently监听接口的consumeMessage()方法的第一个参数为消息列 表,但默认情况下每次只能消费一条消息,可以通过:Consumer的pullBatchSize属性设置消息拉取数量(默认32),可以通过设置consumeMessageBatchMaxSize属性设置消息一次消费数量(默认1)。

[注意]:pullBatchSize 和 consumeMessageBatchMaxSize并不是设置越大越好,一次拉取数据量太大会导致长时间等待,性能降低。而且消息处理失败同一批消息都会失败,然后进行重试,导致消费时长增加。增加没必要的重试次数。

批量消息实战

生产者

我们需要做什么

  • 定义消息切割器切割消息
  • 发送消息把消息切割之后,进行多次批量发送

定义消息切割器

//消息切割器,按照4M大小写个
public class ListSplitter implements Iterator<List<Message>> {
   

    private final int SIZE_LIMIT = 1024 * 1024 * 4;

    private final List<Message> messages;

    private int currIndex;

    public ListSplitter(List<Message> messages) {
    
        this.messages = messages;
    }

    @Override public boolean hasNext() {
   
        return currIndex < messages.size(); 
    }

    @Override public List<Message> next() {
    
        int startIndex = getStartIndex();
        int nextIndex = startIndex;
        int totalSize = 0;
        for (; nextIndex < messages.size(); nextIndex++) {
   
            Message message = messages.get(nextIndex); 
            int tmpSize = calcMessageSize(message);
            if (tmpSize + totalSize > SIZE_LIMIT) {
   
                break; 
            } else {
   
                totalSize += tmpSize; 
            }
        }
        List<Message> subList = messages.subList(startIndex, nextIndex); 
        currIndex = nextIndex;
        return subList;
    }
    private int getStartIndex() {
   
        Message currMessage = messages.get(currIndex); 
        int tmpSize = calcMessageSize(currMessage); 
        while(tmpSize > SIZE_LIMIT) {
   
            currIndex += 1;
            Message message = messages.get(currIndex);
            tmpSize = calcMessageSize(message);
        }
        return currIndex; 
    }
    private int calcMessageSize(Message message) {
   
        int tmpSize = message.getTopic().length() + message.getBody().length;
        Map<String, String> properties = message.getProperties();
        for (Map.Entry<String, String> entry : properties.entrySet()) {
   
            tmpSize += entry.getKey().length() + entry.getValue().length(); 
        }
        tmpSize = tmpSize + 20; // 增加⽇日志的开销20字节
        return tmpSize; 
    }
}

消息发送

public class BatchProducer {
   

    //演示消息同步发送
    public static void main(String[] args) throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
   
        //生产者
        DefaultMQProducer producer = new DefaultMQProducer("batch-producerGroup");

        //设置name server地址
        producer.setNamesrvAddr("127.0.0.1:9876");
        //设置最大消息大小,默认4M
        producer.setMaxMessageSize(1024 * 1024 * 4);
        //启动
        producer.start();


        //===========准备消息==========================================================
        List<Message> messages = new ArrayList<>();

        for (long i = 0 ; i < 10000 ; i++){
   
            //添加内容
            byte[] bytes = ("批量消息".getBytes(CharsetUtil.UTF_8));
            Message message = new Message("topic-order-batch","product-order-batch",bytes);
            message.setKeys("key-"+i);
            messages.add(message);
        }
        //===========切割消息==========================================================

        //把大的消息分裂成若干个小的消息
        ListSplitter splitter = new ListSplitter(messages);

        while (splitter.hasNext()) {
   
            try {
   
                //安装4m切割消息
                List<Message>  listItem = splitter.next();
                //发送消息
                SendResult sendResult = producer.send(listItem);
                System.out.println(sendResult);
            } catch (Exception e) {
   
                e.printStackTrace();
                //处理error
            }
        }

        producer.shutdown();
    }
}

消费者

我们要做什么

  • 可以指定消息拉取数量和消费数量

    public class BatchConsumer {
         
      public static void main(String[] args) throws MQClientException {
         
          //创建消费者
          DefaultMQPushConsumer defaultMQPushConsumer = new DefaultMQPushConsumer("batch-consumerGroup");
          //设置name server 地址
          defaultMQPushConsumer.setNamesrvAddr("127.0.0.1:9876");
          //从开始位置消费
          defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
          //批量拉取消息数量,默认32
          defaultMQPushConsumer.setPullBatchSize(32);
          //每次消费条数,默认1
          defaultMQPushConsumer.setConsumeMessageBatchMaxSize(10);
    
          //订阅
          defaultMQPushConsumer.subscribe("topic-order-batch","product-order-batch");
    
          defaultMQPushConsumer.registerMessageListener(new MessageListenerConcurrently() {
         
              @Override
              public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
         
    
                  list.forEach(message->{
         
                      System.out.println(message+" ; "+new String(message.getBody(), CharsetUtil.UTF_8));
                  });
    
                  return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
              }
          });
    
          defaultMQPushConsumer.start();
      }
    }
    
相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
6月前
|
消息中间件 数据安全/隐私保护 网络架构
Windows下RabbitMQ安装及入门
Windows下RabbitMQ安装及入门
|
16小时前
|
消息中间件 Docker 微服务
RabbitMQ入门指南(十一):延迟消息-延迟消息插件
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了DelayExchange插件、延迟消息插件实现延迟消息等内容。
55 0
|
16小时前
|
消息中间件 微服务
RabbitMQ入门指南(十):延迟消息-死信交换机
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了死信交换机、死信交换机实现延迟消息等内容。
47 0
|
16小时前
|
消息中间件 供应链 Java
RabbitMQ入门指南(九):消费者可靠性
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了消费者确认机制、失败重试机制、失败处理策略、业务幂等性等内容。
43 0
RabbitMQ入门指南(九):消费者可靠性
|
16小时前
|
消息中间件 存储 Java
RabbitMQ入门指南(八):MQ可靠性
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了MQ数据持久化、LazyQueue模式、管理控制台配置Lazy模式、代码配置Lazy模式、更新已有队列为lazy模式等内容。
65 0
|
16小时前
|
消息中间件 JSON Java
RabbitMQ入门指南(六):消息转换器及其案例
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了RabbitMQ默认转换器、JSON转换器及其案例等内容。
39 0
|
16小时前
|
消息中间件 Java API
RabbitMQ入门指南(五):Java声明队列、交换机以及绑定
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了Java声明队列、交换机以及绑定队列和交换机等内容。
34 0
|
16小时前
|
消息中间件 微服务
RabbitMQ入门指南(四):交换机与案例解析
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了交换机在RabbitMQ中的作用与类型、交换机案例(Fanout交换机、Direct交换机、Topic交换机)等内容。
47 0
|
16小时前
|
消息中间件 Java API
RabbitMQ入门指南(三):Java入门示例
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了AMQP、Spring AMQP和使用SpringAMQP实现对RabbitMQ的消息收发等内容。
31 0
RabbitMQ入门指南(三):Java入门示例
|
16小时前
|
消息中间件 存储 数据库
RabbitMQ入门指南(二):架构和管理控制台的使用
RabbitMQ是一个高效、可靠的开源消息队列系统,广泛用于软件开发、数据传输、微服务等领域。本文主要介绍了RabbitMQ架构和管理控制台的使用等内容。
57 0
RabbitMQ入门指南(二):架构和管理控制台的使用