顺序消费rocketMQ(FIFO先进先出)和小技巧 取模运算的周期性特征来将数据分组。

news2025/1/16 0:20:34

20240801

  • 一、顺序消费MQ(FIFO先进先出)
    • 介绍
  • 二、一个小技巧,对于取模运算,用来在几以前进行随机选取,取模运算的周期性特征来将数据分组,
    • 使用场景
    • 对于取模会重复问题

一、顺序消费MQ(FIFO先进先出)

介绍

发送顺序和消费顺序保持一致

默认情况消费方式是并发模式,会导致消息乱序。不管是单线程还是并发模式,都是轮询的模式。也不需要强求全部在一块,只要大局在一块就行。局部有序,不是全局。
在这里插入图片描述
所以,生产者把消息放到一个队列里面去,然后消费者是一个单线程模式。

简单来说流程为:

生产者,把需要顺序的小,都放在一个队列里面,使用send的三个参数的方法,根据某个属性进行规范

消费者,把并发模式修改为顺序模式,然后取拿信息

直接上代码吧,

public class FOrderlyTest {

    private List<MsgModel> msgModels= Arrays.asList(
            new MsgModel("qwer",1,"下单"),
            new MsgModel("qwer",1,"短信"),
            new MsgModel("qwer",1,"物流"),

            new MsgModel("zxcv",2,"下单"),
            new MsgModel("zxcv",2,"短信"),
            new MsgModel("zxcv",2,"物流")

            );
    @Test
    public void  orderlyProducer()throws Exception{
        DefaultMQProducer producer = new DefaultMQProducer("orderly-producer-group");
        producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
        producer.start();
        //发送顺序消息  发送时要确保有序 并且要发到同一个队列下面去
        msgModels.forEach(msgModel -> {
            Message message = new Message("orderlyTopic", msgModel.toString().getBytes());
            //发 相同的订单号去相同的队列
            try {
                producer.send(message, new MessageQueueSelector() {
                    @Override
                    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                      /*  //在这里选择队列,最粗暴的方式
                        return mqs.get(0);//放到第一个队列中*/
                        //2%4=2 3%4=3 4%4=0 5%4=1 6%4=2 7%4=3 8%4=0 9%4=1 10%4=2 11%4=3
                        // 0 1 2 3 0 1 2 3 0 1 2 3 取余时周期函数,结果永远比模数小
                        int hashCode = arg.toString().hashCode();//相同的订单号取相同的hashcode,所以会放到同一队列中
                        int i = hashCode % mqs.size();//取模,放到第i个中
                        return mqs.get(i);//放到第i个队列中
                    }
                }, msgModel.getOrderSn());//msgModel.getOrderSn获取之后会根据订单号去选择队列也就是上面的arg
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        producer.shutdown();
        System.out.println("发送完成");
    }

    @Test
    public void orderlyConsumer()throws Exception{
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("orderly-producer-group");
        consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
        consumer.subscribe("orderlyTopic","*");
      /*  // MessageListenerConcurrently 默认是并发模式 多线程的 默认是20个线程,如果想实现顺序,就把线程设置为1。如果失败,会重试16次,还不成功,就放到死信队列。
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                System.out.println(new String(msgs.get(0).getBody()));
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });*/
        //MessageListenerOrderly 顺序消费模式 单线程的。无线重试,Integer.MAX_VALUE A不走,B拿不到
        consumer.registerMessageListener(new MessageListenerOrderly() {

            @Override
            public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
                System.out.println("线程id:"+Thread.currentThread().getId());
                System.out.println(new String(msgs.get(0).getBody()));
                // 顺序消费模式,如果消费失败,会自动重试   SUSPEND_CURRENT_QUEUE_A_MOMENT 表示当前队列暂停消费
                return ConsumeOrderlyStatus.SUCCESS;
            }
        });

        consumer.start();
        System.in.read();
    }
}

实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MsgModel {
    private String orderSn;
    private Integer userId;
    private String desc;//下单 短信 物流


}

二、一个小技巧,对于取模运算,用来在几以前进行随机选取,取模运算的周期性特征来将数据分组,

因为取模时周期函数,结果永远比模数小,所以如果我们定义为4,那我们给所有元素取哈希,相同的一定会被分到一块,因为统一元素的hash值是一样的。

当我们想在很多不同的订单中拿到相同的(少量的),可以对其进行取模,把相同的放到一块
如:

try {
                producer.send(message, new MessageQueueSelector() {
                    @Override
                    public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                      /*  //在这里选择队列,最粗暴的方式
                        return mqs.get(0);//放到第一个队列中*/
                        //2%4=2 3%4=3 4%4=0 5%4=1 6%4=2 7%4=3 8%4=0 9%4=1 10%4=2 11%4=3
                        // 0 1 2 3 0 1 2 3 0 1 2 3 取余时周期函数,结果永远比模数小
                        int hashCode = arg.toString().hashCode();//相同的订单号取相同的hashcode,所以会放到同一队列中
                        int i = hashCode % mqs.size();//取模,放到第i个中
                        return mqs.get(i);//放到第i个队列中
                    }
                }, msgModel.getOrderSn());//msgModel.getOrderSn获取之后会根据订单号去选择队列也就是上面的arg
            } catch (Exception e) {
                e.printStackTrace();
            }
       

使用场景

这个小技巧使用了取模运算的周期性特征来将数据分组,这在许多实际应用场景中都很有用。以下是一些常见的应用场景:

  1. 负载均衡
    在分布式系统中,负载均衡是将请求分配到不同的服务器上。通过对请求的哈希值取模,可以将相同的请求分配到同一台服务器上,从而提高缓存效率和减少重复计算。
  2. 哈希表
    在哈希表中,取模运算用于将键值映射到表的索引位置。这样可以将相似的键值分配到相同的桶中,方便快速查找。
  3. 缓存
    在缓存系统中,可以使用取模运算将相同的缓存数据分配到相同的缓存区域。这有助于提高缓存命中率,并减少不必要的缓存重新加载。
  4. 分片存储
    在数据库系统中,数据分片是将数据分布到多个物理存储节点上的技术。通过对数据的哈希值取模,可以将相同的数据分配到同一个分片上,从而简化数据管理。
  5. 任务调度
    在任务调度系统中,取模运算可以将任务分配到不同的处理单元或队列中。通过这种方式,可以确保相同类型的任务集中在一个队列中,便于管理和处理。
  6. 负载均衡算法
    在一些应用中,使用取模运算来分配资源或任务。比如在分布式计算中,可以将相同的任务分配到相同的计算节点,以保证任务的连续性和一致性。

总之,利用取模运算的周期性和哈希的特性可以在多个场景中高效地分配和管理数据,从而提高系统的性能和稳定性。

对于取模会重复问题

取模运算可能会导致哈希冲突,即不同的输入值经过取模后得到相同的结果。这种情况通常发生在模数较小或者数据量较大时。在处理这些重复或冲突时,可以考虑以下几种方法来优化:

  1. 增大模数
    如果取模运算的模数较小,容易造成重复。可以考虑增大模数,这样可以降低冲突的概率。例如,将模数设置为更大的质数,可以减少不同数据项取模后结果相同的情况。
  2. 使用更复杂的哈希函数
    选择适当的哈希函数可以减少冲突的发生。好的哈希函数能够将不同的输入均匀地分布到哈希表中,即使在相同的模数下,也能尽量减少冲突。
  3. 链表法
    在哈希表中,如果多个元素的哈希值取模后相同,可以使用链表法解决冲突。每个哈希桶可以维护一个链表来存储所有哈希值相同的元素。
  4. 开放地址法
    另一种解决冲突的方式是开放地址法。当发生冲突时,寻找下一个可用的位置存储元素。常见的开放地址法有线性探测、二次探测和双重哈希等。
  5. 双重哈希
    双重哈希是一种解决冲突的方法。在第一次哈希之后,如果发生冲突,再进行第二次哈希运算,结合两个哈希值来确定最终的位置,从而减少冲突。
  6. 分布式哈希表(DHT)
    在分布式系统中,可以使用分布式哈希表技术将数据均匀分布到多个节点上。DHT能更有效地处理数据冲突和负载均衡问题。
  7. 一致性哈希
    一致性哈希是一种改进的哈希技术,能有效减少节点变动对系统的影响,并降低数据冲突的几率。它常用于分布式系统中的负载均衡和数据分片。

通过这些方法,可以有效地管理哈希冲突,并提高系统的性能和稳定性。在实际应用中,可以根据具体需求选择合适的策略来解决取模运算带来的重复问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1968243.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

openeuler下载docker

https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/rhel/9/x86_64/stable/ #清华的网址 https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable/ #阿里云的网址 开始配置 vim /etc/yum.repos.d/docker-ce.repo #写仓库&#xff0c;我这里…

【初阶数据结构篇】归并排序和计数排序(总结篇)

文章目录 归并排序和计数排序前言代码位置归并排序计数排序排序性能比较排序算法复杂度及稳定性分析 归并排序和计数排序 前言 本篇以排升序为例 代码位置 gitee 前篇&#xff1a;【初阶数据结构篇】冒泡排序和快速排序 中篇&#xff1a;【初阶数据结构篇】插入、希尔、选择…

【Qt】QDateTimeEdit

在Qt中&#xff0c;QDateEdit是用于选择日期的微调框&#xff0c;QTimeEdit是用于选择小时和分钟的微调框 QDateTimeEdit则是基于QDateEdit和QTimeEdit的组合控件&#xff0c;能够同时显示日期和时间&#xff0c;并允许用户以交互方式编辑日期 常用属性 属性说明dateTime时间…

electron-updater实现electron全量更新和增量更新——渲染进程UI部分

同学们可以私信我加入学习群&#xff01; 正文开始 前言更新功能所有文章汇总一、两个同心球效果实现二、球内进度条、logo、粒子元素实现2.1 球内包含几个元素&#xff1a;2.2 随机粒子生成方法generateRandomPoint2.3 创建多个粒子的方法createParticle 三、gsap创建路径动画…

基于python的百度迁徙迁入、迁出数据分析(六)

书接上回&#xff0c;苏州市我选取了2024年5月1日——5月5日迁入、迁出城市前20名并求了均值&#xff0c;从数据中可以看出苏州市与上海市的关系还是很铁的&#xff0c;都互为对方的迁入、迁出的首选且迁徙比例也接近4分之一&#xff0c;名副其实的老铁了&#xff1b; 迁出城市…

Seurat-SCTransform与harmony整合学习续(亚群分析)

目录 提取细胞亚群 SCTransform-harmony技术路线 ①亚群SCTransform标准化 ②harmony去批次 这里对上一章的内容进行补充&#xff1a; Seurat-SCTransform与harmony整合学习-CSDN博客 提取细胞亚群 rm(list ls()) library(Seurat)#好像先后需要先后加载 library(patchw…

【Jenkins】在linux上通过Jenkins编译gitee项目

因项目需求近期在linux服务器上部署了Jenkins来自动编译gitee上的项目源码&#xff0c;期间踩到了一些坑&#xff0c;花费了不少时间来处理&#xff0c;特此记录。 所需资源下载列表&#xff1a; Jenkins &#xff1a;https://mirrors.tuna.tsinghua.edu.cn/jenkins/war/2.46…

文件系统 --- 重定向,缓冲区

序言 本篇文章的内容和上一篇文章 &#x1f449;点击查看 紧密相连&#xff0c;所以为了更好的理解本篇文章&#xff0c;需要大家将前置知识准备好哦&#x1f607;。  本文主要向大家介绍文件的重定向&#xff0c;以及基于用户级别的缓冲区和基于操作系统级别的缓冲区。原来看…

AI技术和大模型对人才市场的影响

012024 AI技术和大模型 2024年AI技术和大模型呈现出多元化和深入融合的趋势&#xff0c;以下是一些关键的技术方向和特点&#xff1a; 1. 生成式AI 生成式AI&#xff08;Generative AI&#xff09;在2024年继续快速发展&#xff0c;它能够创造全新的内容&#xff0c;而不仅仅…

Redis——有序集合

目录 1. 添加元素 ZADD 2. 查看全部元素 ZRANGE 3. 查看某个元素的分数 ZSCORE 4. 查看元素的排名 ZRANK SortedSet 也叫 ZSet ,即有序集合&#xff0c; 有序集合与集合的区别&#xff1a; 有序集合的每个元素都会关联一个浮点类型的分数&#xff0c;依赖该分数的的大小对…

《Milvus Cloud向量数据库指南》——多模态融合新纪元:音频、视频与文本的无缝转换

在探讨多模态数据处理与应用的广阔领域中,多模态文本、音频、视频数据的融合与交互成为了近年来人工智能研究的热点之一。这一趋势不仅推动了技术的深度发展,也为众多行业带来了前所未有的创新机遇。本文将深入剖析多模态文本-音频与多模态文本-视频RAG(Retrieval-Augmented…

书生大模型基础岛-第三关:LangGPT结构化提示词编写实践

1.来源和任务 来源&#xff1a; https://github.com/InternLM/Tutorial/blob/camp3/docs/L1/Prompt/task.md 任务&#xff1a; 背景问题&#xff1a;近期相关研究发现&#xff0c;LLM在对比浮点数字时表现不佳&#xff0c;经验证&#xff0c;internlm2-chat-1.8b (internlm2-…

C++——list容器以及手动实现

LIST容器 list概述列表容器属性例子 list函数构造函数默认构造函数&#xff1a;带有元素个数和元素初值的构造函数&#xff1a;范围构造函数&#xff1a;拷贝构造函数&#xff1a;移动构造函数&#xff1a;示例 赋值运算符重载拷贝赋值操作符 (1)&#xff1a;移动赋值操作符 (2…

安全通信|数据加密的由来|加密算法简介|中间人攻击与证书认证|身份验证

&#x1f448;️下一篇 计算机网络-专栏&#x1f448;️ 数据加密的由来|加密算法简介|中间人攻击与证书认证 引言 在客户端(client)-服务器(server)模式下&#xff0c;客户端与服务器间通信&#xff0c;如果明文传输数据&#xff0c;在传输过程被劫持&#xff0c;内容直接泄…

MySQL触发器和存储过程

1、触发器 &#xff08;1&#xff09;&#xff1a;建立触发器&#xff0c;订单表中增加订单数量后&#xff0c;商品表商品数量同步减少对应的商品订单出数量,并测试 mysql> create trigger orders_after_insert_trigger-> after insert on orders for each row-> up…

不知道你们有没有我这样的一种状态...总是这样又总是那样...

各位小伙伴们&#xff0c;我是风尚&#xff0c;我不知道你们有没有那么一刻&#xff0c;就是感觉站在人生的十字路口&#xff0c;感觉自己就像是被扔进了一个没有导航的迷宫&#xff0c;四周都是墙&#xff0c;头顶是蓝天白云&#xff0c;却怎么也找不到出口的方向&#xff1f;…

重磅推荐!GBD再度登顶Lancet!| GBD数据库周报(7.17~7.23)

全球疾病负担&#xff08;GBD&#xff09;是迄今为止规模最大、最全面的一项研究&#xff0c;旨在量化不同地区和不同时期的健康损失&#xff0c;从而改善卫生系统并消除差异。 该研究由华盛顿大学健康指标与评估研究所 (IHME) 牵头&#xff0c;是一项真正的全球性研究&#xf…

MySQL--数据库与表的操作

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 数据库的基本操作 # 1、查看数据库show databases;​# 2、创建数据库create database 数据库名称;​# 3、删除数据库drop databse 数据库名称; 数据表…

RAC(Teamcenter )开发,Bom行解包和打包的方法

1、打包 UnpackAllAction allAction new UnpackAllAction((AbstractBOMLineViewerApplication) currentApplication, "packAllAction"); new Thread(allAction).start();2、解包 UnpackCommand command new UnpackCommand(bomLine); command.executeModal();3、注…