首页 > 其他分享 >20第四章:05_批量消息

20第四章:05_批量消息

时间:2022-08-14 19:34:58浏览次数:62  
标签:20 批量 05 messages 发送 4M 消息 public 第四章

一、批量发送消息

发送限制

生产者进行消息发送时可以一次发送多条消息,这可以大大提升 Producer 的发送效率。不过需要注意以下几点:

  • 批量发送的消息必须具有相同的 Topic
  • 批量发送的消息必须具有相同的刷盘策略
  • 批量发送的消息不能是延时消息与事务消息

批量发送大小

默认情况下,一批发送的消息总大小不能超过 4MB 字节。如果想超出该值,有两种解决方案:

  • 方案一:将批量消息进行拆分,拆分为若干不大于 4M 的消息集合分多次批量发送
  • 方案二:在 Producer 端与 Broker 端修改属性
    • Producer 端需要在发送之前设置 Producer 的 maxMessageSize 属性
    • Broker 端需要修改其加载的配置文件中的 maxMessageSize 属性

生产者发送的消息大小

生产者通过 send()方法发送的 Message,并不是直接将 Message 序列化后发送到网络上的,而是通过这个 Message 生成了一个字符串发送出去的。这个字符串由四部分构成:Topic、消息 Body、消息日志(占 20 字节),及用于描述消息的一堆属性 key-value。这些属性中包含例如生产者地址、生产时间、要发送的 QueueId 等。最终写入到 Broker 中消息单元中的数据都是来自于这些属性。

二、 批量消费消息

修改批量属性

Consumer 的 MessageListenerConcurrently 监听接口的 consumeMessage()方法的第一个参数为消息列表,但默认情况下每次只能消费一条消息。若要使其一次可以消费多条消息,则可以通过修改 Consumer 的 consumeMessageBatchMaxSize 属性来指定。不过,该值不能超过 32。因为默认情况下消费者每次可以拉取的消息最多是 32 条。若要修改一次拉取的最大值,则可通过修改 Consumer 的 pullBatchSize 属性来指定。

存在的问题

Consumer 的 pullBatchSize 属性与 consumeMessageBatchMaxSize 属性是否设置的越大越好?当然不 是。

  • pullBatchSize 值设置的越大,Consumer 每拉取一次需要的时间就会越长,且在网络上传输出现问题的可能性就越高。若在拉取过程中若出现了问题,那么本批次所有消息都需要全部重新拉取。
  • consumeMessageBatchMaxSize 值设置的越大,Consumer 的消息并发消费能力越低,且这批被消费的消息具有相同的消费结果。因为 consumeMessageBatchMaxSize 指定的一批消息只会使用一个线程进行处理,且在处理过程中只要有一个消息处理异常,则这批消息需要全部重新再次消费处理。

三、代码举例

该批量发送的需求是,不修改最大发送 4M 的默认值,但要防止发送的批量消息超出 4M 的限制。

定义消息列表分割器

// 消息列表分割器:其只会处理每条消息的大小不超4M的情况。
// 若存在某条消息,其本身大小大于4M,这个分割器无法处理,
// 其直接将这条消息构成一个子列表返回。并没有再进行分割
public class MessageListSplitter implements Iterator<List<Message>> {
    // 指定极限值为4M
    private final int SIZE_LIMIT = 4 * 1024 * 1024;
    // 存放所有要发送的消息
    private final List<Message> messages;
    // 要进行批量发送消息的小集合起始索引
    private int currIndex;

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

    @Override
    public boolean hasNext() {
        // 判断当前开始遍历的消息索引要小于消息总数
        return currIndex < messages.size();
    }

    @Override
    public List<Message> next() {
        int nextIndex = currIndex;
        // 记录当前要发送的这一小批次消息列表的大小
        int totalSize = 0;
        for (; nextIndex < messages.size(); nextIndex++) {
            // 获取当前遍历的消息
            Message message = messages.get(nextIndex);

            // 统计当前遍历的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;

            // 判断当前消息本身是否大于4M
            if (tmpSize > SIZE_LIMIT) {
                if (nextIndex - currIndex == 0) {
                    nextIndex++;
                }
                break;
            }

            if(tmpSize + totalSize > SIZE_LIMIT) {
                break;
            } else{
                totalSize += tmpSize;
            }
        } // end-for

        // 获取当前messages列表的子集合[currIndex, nextIndex)
        List<Message> subList = messages.subList(currIndex, nextIndex);
        // 下次遍历的开始索引
        currIndex = nextIndex;
        return subList;
    }
}

定义批量消息生产者

public class BatchProducer {
    public static void main(String[] args) throws Exception {
        DefaultMQProducer producer = new DefaultMQProducer("pg");
        producer.setNamesrvAddr("rocketmqOS:9876");
        // 指定要发送的消息的最大大小,默认是4M
        // 不过,仅修改该属性是不行的,还需要同时修改broker加载的配置文件中的
        // maxMessageSize属性
        // producer.setMaxMessageSize(8 * 1024 * 1024);
        producer.start();
        // 定义要发送的消息集合
        List<Message> messages = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            byte[] body = ("Hi," + i).getBytes();
            Message msg = new Message("someTopic", "someTag", body);
            messages.add(msg);
        }
        //定义消息列表分割器,将消息列表分割为多个不超出4M大小的小列表
        MessageListSplitter splitter = new
                MessageListSplitter(messages);
        while (splitter.hasNext()) {
            try {
                List<Message> listItem = splitter.next();
                producer.send(listItem);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        producer.shutdown();
    }
}

定义批量消息消费者

public class BatchConsumer {
    public static void main(String[] args) throws MQClientException {
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("cg");
        consumer.setNamesrvAddr("rocketmqOS:9876");
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        consumer.subscribe("someTopicA", "*");
        // 指定每次可以消费10条消息,默认为1
        consumer.setConsumeMessageBatchMaxSize(10);
        // 指定每次可以从Broker拉取40条消息,默认为32
        consumer.setPullBatchSize(40);
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus
            consumeMessage(List<MessageExt> msgs,
                           ConsumeConcurrentlyContext context) {
                for (MessageExt msg : msgs) {
                    System.out.println(msg);
                }

                // 消费成功的返回结果
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                // 消费异常时的返回结果
                // return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
        });
        consumer.start();
        System.out.println("Consumer Started");
    }
}

标签:20,批量,05,messages,发送,4M,消息,public,第四章
From: https://www.cnblogs.com/niujifei/p/16586110.html

相关文章

  • [2011年NOIP提高组] 铺地毯
    为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有n张地毯,编号从1到n。现在将这些地毯按照编号从小到大......
  • [2016年NOIP普及组] 回文日期
    [2016年NOIP普及组]回文日期题目大意:用 8 位数字表示一个日期,其中,前 4 位代表年份,接下来 2 位代表月 份,最后 2 位代表日期,一个日期是回文的,当且仅当表示这个日......
  • NC16496 [NOIP2014]飞扬的小鸟
    题目链接题目题目描述为了简化问题,我们对游戏规则进行了简化和改编:\1.游戏界面是一个长为n,高为m的二维平面,其中有k个管道(忽略管道的宽度)。\2.小鸟始终在游戏界......
  • [NOIP2001 提高组] 一元三次方程求解
    试题描述:输入一行,4个实数a,b,c,d输出一行,3个实根,从小到大输出,并精确到小数点后2位。样例输入1-5-420样例输出-2.002.005.00#include<bits/stdc+......
  • [NOIP2001 提高组] 一元三次方程求解
    [NOIP2001提高组]一元三次方程求解分析:由题意得,本题要求的是一元三次方程等于0时的三个根,由图像我们可知等于0时的根左右两侧的点的纵坐标乘积(也就是根)为负数,因为题目......
  • [2000年NOIP普及组] 税收与补贴问题
    [2000年NOIP普及组]税收与补贴问题思路:先开一个二维数组,将商品在各个价位的销售量以表格的方式记录下来,再加上补贴或税收,得出最大利润与期望的比较,最后输出代码如下:#in......
  • [2000年NOIP普及组] 税收与补贴问题
     价格枚举范围,只要销量不为0就一直枚举。因销量有两个区间,故枚举时要注意。该题要注意,最小值在绝对值中产生,要注意输出结果有正有负。    ......
  • P1190 [NOIP2010 普及组] 接水问题(嵌套循环——贪心算法)
    学校里有一个水房,水房里一共装有mm个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为11。现在有nn名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺......
  • 2022河南萌新联赛第(六)场:郑州大学 (ACDFHKL)
    https://ac.nowcoder.com/acm/contest/39114C盲打(模拟)大写的时候就多个shift键就......
  • week03-day05练习
    <script>//1,使用reduce求数组中所有元素的乘积,//vararr=[2,3,4,5,6,7]vararr01=[2,3,4,5,6,7];varresult=arr01......