RabbitMQ实现秒杀场景示例

news2024/11/18 23:32:41

本文章通过MQ队列来实现秒杀场景

整体的设计如下图,整个流程中对于发送发MQ失败和发送到死信队列的数据未做后续处理

1、首先先创建MQ的配置文件

@Configuration
public class RabbitConfig  {


    public static final String DEAD_LETTER_EXCHANGE = "deadLetterExchange";
    public static final String DEAD_LETTER_QUEUEA_ROUTING_KEY = "dead.#";
    public static final String DEAD_LETTER_QUEUEA_NAME = "deadQueue";

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ConnectionFactory connectionFactory;

    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange("seckill_topic",true,false);
    }

    // 声明死信Exchange
    @Bean("deadLetterExchange")
    public DirectExchange deadLetterExchange(){
        return new DirectExchange(DEAD_LETTER_EXCHANGE);
    }

    @Bean("seckillQueue")
    public Queue seckillQueue(){
        Map<String,Object> args = new HashMap<>();
        args.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);
        //  x-dead-letter-routing-key  这里声明当前队列的死信路由key
        args.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUEA_ROUTING_KEY);
        return QueueBuilder.durable("seckillQueue").withArguments(args).build();

    }

    @Bean("deadQueue")
    public Queue binding(){
        return new Queue(DEAD_LETTER_QUEUEA_NAME);

    }

    @Bean
    public Binding bindingExchange(){
        return BindingBuilder.bind(seckillQueue()).to(topicExchange()).with("seckill.#");

    }

    // 声明死信队列绑定关系
    @Bean
    public Binding deadLetterBinding(@Qualifier("deadQueue") Queue queue,
                                      @Qualifier("deadLetterExchange") DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(DEAD_LETTER_QUEUEA_ROUTING_KEY);
    }

    //配置会覆盖yml的重试次数
    //RabbitMQ监听容器
    /*@Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory){
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        //设置并发
        factory.setConcurrentConsumers(1);
        SimpleMessageListenerContainer s=new SimpleMessageListenerContainer();
        //最大并发
        factory.setMaxConcurrentConsumers(1);
        //消息接收——手动确认
        factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
        //设置超时
        factory.setReceiveTimeout(2000L);
        //设置重试间隔
        factory.setFailedDeclarationRetryInterval(3000L);

        //监听自定义格式转换
        //factory.setMessageConverter(jsonMessageConverter);
        return factory;
    }*/
}

2、配置yml文件

spring:
  redis:
    database: 0
    host: xxx
    port: 6379
    password: xxx
    timeout: 60
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 8
        min-idle: 0
  rabbitmq:
    username: admin
    password: admin
    virtual-host: /
    host: xxxx
    port: 12345
    publisher-confirms: true
    publisher-returns: true
    template:
      mandatory: true
    listener:
      simple:
        concurrency: 1
        max-concurrency: 3
        # 消费者预取1条数据到内存,默认为250条
        prefetch: 1
        # 确定机制
        acknowledge-mode: manual
        retry:
          enabled: true #是否支持重试
          max-attempts: 2
          # 重试间隔(ms)
          initial-interval: 5000

这里有一点需要注意的是在做死信队列的时候如果Config文件中配置了监听容器,在yml文件中的一些属性要在容器里面进行配置,当时测试重试的时候发现没有在Config文件中配置,只在yml文件中配置了重试次数,结果会无限期的重试,MQ的默认方式就是无限期的重试,所以这点很容易踩坑

3、实现交换机的ACK,实现 RabbitTemplate.ConfirmCallback接口

@Component
public class ConfirmCallBackHandler implements RabbitTemplate.ConfirmCallback {

    @Autowired
    private RabbitMessageMapper rabbitMessageMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    //注入
    //PostConstruct注解会在Component、Autowired注解完成后再执行
    @PostConstruct
    public void init(){
        rabbitTemplate.setConfirmCallback(this);
    }


    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        if(!ack){
            RabbitMessage rabbitMessage = new RabbitMessage();
            rabbitMessage.setUniqueKey(correlationData.getId().toString());
            rabbitMessage.setSuccessFlag("N");
            rabbitMessageMapper.updateSuccessFlag(rabbitMessage);
            System.out.println("失败原因:"+cause);
        }
    }
}

4、实现队列的ACK,实现 RabbitTemplate.ReturnCallback

@Component
public class ReturnCallBackHandler implements RabbitTemplate.ReturnCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    //注入
    //PostConstruct注解会在Component、Autowired注解完成后再执行
    @PostConstruct
    public void init(){
        rabbitTemplate.setReturnCallback(this);
    }

    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        System.out.println("消息主体 message:"+message);
        System.out.println("应答码 replyCode: :"+replyCode);
        System.out.println("原因描述 replyText:"+replyText);
        System.out.println("交换机 exchange:"+exchange);
        System.out.println("消息使用的路由键 routingKey:"+routingKey);
    }
}

5、消费者方面,实现 ChannelAwareMessageListener 接口

@Component
public class AckListener implements ChannelAwareMessageListener {

    @Autowired
    private RabbitMqService rabbitMqService;

    @RabbitListener(queues = "seckillQueue")
    @Override
    public void onMessage(Message messagex, Channel channel) throws Exception {
        try {
            String result = new String(messagex.getBody(),"utf-8");
            rabbitMqService.receive(result);

            channel.basicAck(messagex.getMessageProperties().getDeliveryTag(), false);
        }catch (Exception exception){
            channel.basicNack(messagex.getMessageProperties().getDeliveryTag(), false, false);
        }
    }
}

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

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

相关文章

springcloud3 分布式事务-seata的四种模式总结以及异地容灾

一 seata四种模式比较 1.1 seata的4种模式比较 二 seata的高可用 2.1架构 1.建TC服务集群非常简单&#xff0c;启动多个TC服务&#xff0c;注册到nacos即可。 2.做异地多机房容灾&#xff0c;比如一个TC集群在上海&#xff0c;另一个TC集群在杭州&#xff0c; 3.微服务基…

趣解设计模式之《小王的糖果售卖机》

〇、小故事 小王最近一直在寻找商机&#xff0c;他发现商场儿童乐园或者中小学校周围&#xff0c;会有很多小朋友喜欢吃糖果&#xff0c;那么他想设计一款糖果售卖机&#xff0c;让后将这些糖果售卖机布置到商场和学校旁边&#xff0c;这样就能获得源源不断的收益了。 想到这里…

20 个实例玩转 Java 8 Stream

20 个实例玩转 Java 8 Stream 1、Stream概述 Java 8 是一个非常成功的版本&#xff0c;这个版本新增的 Stream&#xff0c;配合同版本出现的 Lambda&#xff0c;给我们操作集合 Collection 提供了极大的便利。 那么什么是 Stream&#xff1f; Stream 将要处理的元素集合看作…

Docker部署MySQL8数据库

1、准备工作 docker pull mysql:8.0.27 Pwd"/data/software/mysql" mkdir ${Pwd}/{data,logs} -p chmod 777 ${Pwd}/logs2、添加配置文件 cat > ${Pwd}/my.cnf << EOF [mysqld] usermysql pid-file/var/run/mysqld/mysqld.pid socket/var/run/mysqld/mysq…

SQL和Python,哪个更容易自学?哪个更适合数据工作的编程新手?

如果你想从事数据工作&#xff0c;比如数据分析、数据开发、数据科学等&#xff0c;你可能会遇到这样的问题&#xff1a;SQL和Python哪个更容易自学&#xff1f;哪个更有用&#xff1f;哪个更有前途&#xff1f;其实这两种语言都是数据工作的重要技能&#xff0c;但它们的特点和…

react实现数据进度条展示组件

1.需求 在项目开发时&#xff0c;要展示一个操作的进度条&#xff0c;比如&#xff1a;要实现一个文件的上传下载进度条&#xff0c;或者实现类似拼夕夕砍一刀进度条&#xff0c;怎么实现呢&#xff1f;效果图如下&#xff1a; 对上面效果图说明&#xff1a; 进度条底色为棕黑色…

559. N 叉树的最大深度

给定一个 N 叉树&#xff0c;找到其最大深度。 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 N 叉树输入按层序遍历序列化表示&#xff0c;每组子节点由空值分隔&#xff08;请参见示例&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [1,null,3,2…

从统计语言模型到预训练语言模型---预训练语言模型(BERT,GPT,BART系列)

基于 Transformer 架构以及 Attention 机制&#xff0c;一系列预训练语言模型被不断提出。 ​BERT 2018 年 10 月&#xff0c; Google AI 研究院的 Jacob Devlin 等人提出了 BERT (Bidirectional Encoder Representation from Transformers ) 。具体的研究论文发布在 arXiv …

浅谈低压绝缘监测及定位系统在海上石油平台的研究与应用

安科瑞 华楠 摘要&#xff1a;海上石油平台低压系统与陆地电力系统有很大区别&#xff0c;其属于中性点绝缘系统&#xff0c;在出现单相接地故障时&#xff0c;系统允许带故障正常运行2 h&#xff0c;保证海上重要电气设备不会立即关停。现以渤海某海上平台为例&#xff0c;其…

LABVIEW 实战案例1--温度报警系统

图1 温度报警系统前面板 图2 温度报警系统后面板

1796_通过vmware打开VirtualBox虚拟机文件

全部学习汇总&#xff1a; GitHub - GreyZhang/toolbox: 常用的工具使用查询&#xff0c;非教程&#xff0c;仅作为自我参考&#xff01; 首先讲vdi格式转换成vmdk格式&#xff0c;以我自己的环境下的信息&#xff0c;处理如下&#xff1a; VBoxManage clonehd "LinuxMin…

Sentinel结合Nacos实现配置持久化(全面)

1、前言 我们在进行分布式系统的开发中&#xff0c;无论是在开发环境还是发布环境&#xff0c;配置一定不能是内存形式的&#xff0c;因为系统可能会在中途宕机或者重启&#xff0c;所以如果放在内存中&#xff0c;那么配置在服务停到就是就会消失&#xff0c;那么此时就需要重…

javascript 使用async/await简化异步操作实践

实现的功能简述&#xff1a; 新增申请单时&#xff0c;申请单的业务日期由两个因素决定&#xff1a; 异步获取的仓库的业务日期。异步获取的日期偏移天数规则。 业务日期 仓库的业务日期 偏移天数。比如仓库的业务日期是2023-01-01,偏移天数是5&#xff0c;那么最终的业务日期…

【轨道机器人】成功驱动伺服电机(学生电源、DCH调试软件、DH系列伺服驱动器)

1、硬件平台 工控机 学生电源 DH系列伺服驱动器 电机 调试平台&#xff1a;DCH 2、如何利用dch驱动电机 点击可驱动电机 下面的步骤是比较关键的几步&#xff1a; 3、遇到的问题 不能成功驱动电机&#xff0c;还和厂家那边打电话&#xff0c;询问 发现是这…

霍金《时间简史》A Brief History of Time 学习笔记(第二章)

CHAPTER 2 : SPACE & TIME Footnote: Second chapter. Mainly talks about spacetime. Footnote: “Thought Experiment”, which is quite common in the field of physics. False: Galileo dropping weights from the Tower of Pisa (Assertedly) True: Galileo rolling…

【企业级SpringBoot单体项目模板 】——Mybatis-plus自动代码生成

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;SpringBoot项目模版、企业级、模版☀️每日 一言&#xff1a;我们之所以这样认为&#xff0c;是因为他们这样说。他们之所以那样说&#xff0c;是因为他们想让我们那样认为。所以实践才是检验真理…

漏刻有时数据可视化Echarts组件开发(30):自定义方向的数据流向动画

let points = [{name: 市城市管理局,desc: {type: 1,},},{name: 科大讯飞,desc: {type: 2,},},{name: 市水利局,desc: {type: 1,},},{name: 市政法委,desc: {type: 1,},},{name: 市自然资源和规划局,desc: {type: 1,},},{name: 市生态环境局,desc: {type: 1,},},{name: 市大数据…

资源分享 | 情绪脑电研究公开数据集

SEED SEED数据集是由上海交大类脑计算与机器智能研究中心(BCMI)开发的。该数据集是基于脑电的情绪分类任务而设计的数据集。该数据集记录了15名被试在观看积极、中性和消极情绪电影片段时的EEG信号&#xff0c;每个视频片段的时间为3-5分钟。每个参与者重复采集三天&#xff0…

BST搜索二叉树

目录 二叉搜索树概念 ​编辑 1 二叉搜索树的构建 2. 二叉搜索树的删除 3二叉搜索树中放入元素 4. 二叉搜索树中元素的删除 5. 二叉搜索树中元素的遍历 6 二叉搜索树中元素的查找 7二叉搜索树的拷贝构造 二叉搜索树概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一…

【lesson10】fork创建进程的现象解答

文章目录 fork现象fork问题 fork现象 我们先来看一段代码。 大家觉得这段代码的printf会打印几次&#xff1f; 结果&#xff1a; 我们可以清楚的看到&#xff0c;第二个printf打印了2次。 我们再来看一段不可思议的代码&#xff1a; 运行结果&#xff1a; 我们可以看到这r…