Java高性能高并发实战之Rabbitmq接口优化(六)

本文是Java高性能高并发实战系列的第六篇,主要介绍如何使用RabbitMQ进行接口优化,特别是针对秒杀场景。通过Redis预加载库存、预减库存以及使用RabbitMQ异步下单,降低数据库访问压力。文章详细讲解了RabbitMQ的Direct、Topic、Fanout和Header四种交换机模式,并展示了秒杀接口的优化过程,包括前端和后端的设计与测试。
摘要由CSDN通过智能技术生成

前言

这是系列的第六篇文章接口优化设计首先来回顾一下之前的几篇文章:

章节名称 博客地址
安装部署Redis 集成Redis(已完结)
页面登陆功能设计 登录功能设计(更新优化中)
秒杀页面具体设计 秒杀详情页(已完结)
JMeter初级压测学习 Jmeter压测入门学习(已完结)
页面优化设计 页面优化设计(已完结)
接口优化 RabbbitMq接口优化(已完结)
图形验证码等 图形验证码及接口防刷(更新优化中)

在前面的第五篇介绍到了页面优化技术,但是对于秒杀来说仅仅在前端做一些缓存的处理和页面静态化就想解决高并发访问的问题未免太过于天真了,并且对于一个前后端分离的项目来说,就更需要后端的一些技术支持。这一节就来具体介绍一些关于接口优化的方案。具体代码参见我的个人github源码

对于接口的优化处理主要有以下的几个部分:

  1. Redis预减库存来减少数据库访问。
  2. 内存标记来介绍Redis访问。
  3. 将请求先行放入到缓冲队列中,异步下单。
  4. nginx水平扩展。

思路

  1. 首先在系统初始化时候,就把商品的数量加载到Redis里面。进行提前的加载操作。
  2. 收到请求以后 Redis预减库存,就是reids先对库存进行一个减操作,库存不足的时候直接就回返回错误信息。
    思考会有什么好处:例如我们就有100件商品,此时数据的加载时候就会预先加载到redis中,前端对数据进行请求,完成了100件订单以后,对于后续的订单就算是来再多也会显示没有了库存就不会请求到数据库,此时对数据库的访问几乎是零。
  3. 对于库存充足的情况下就会进入到第三步,将请求的信息入队(rabbitmq队列)。立即返回的是排队中 。不是返回成功或者失败,因为是入队但是还不能判断是否成功。
  4. 客户端会进行轮询操作,自己的这次请求是成功还是失败了 。对于服务端来说:将请求出队(就是放在队列中待执行的请求进行执行操作)生成订单,减少库存。

Rabbitmq安装与整合

  1. 首先在自己的电脑上安装Rabbitmq并进行启动,这里若是没有安装的小伙伴可以参看下面这篇文章,不仅有详细的安装方法,还附带百度云盘供大家下载对应的版本下载与安装
  2. 完成安装以后启动起来,既然是和Spring Boot进行整合操作急需要添加依赖,添加如下依赖在自己的pom.xml文件中
<dependency>  
		<groupId>org.springframework.boot</groupId>  
		<artifactId>spring-boot-starter-amqp</artifactId>  
	</dependency>  
  1. 添加配置信息,这里的配置文件是properties如下:
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
# 因为我们的客户端在连接本地的rabbitmq时候并不是真正意义上连接到服务器上,对于服务器来说也会虚拟出很多的服务器,供不同的客户端建立连接,每个虚拟的服务器之间都是相互独立的,默认就是一个斜杠来访问。
#\u6D88\u8D39\u8005\u6570\u91CF
spring.rabbitmq.listener.simple.concurrency= 10
# 消费者数量,定义是1的时候 表示就一个消费者,此时就是串行化执行。
spring.rabbitmq.listener.simple.max-concurrency= 10
#\u6D88\u8D39\u8005\u6BCF\u6B21\u4ECE\u961F\u5217\u83B7\u53D6\u7684\u6D88\u606F\u6570\u91CF
spring.rabbitmq.listener.simple.prefetch= 1
# 每次取出来几个从队列中。也可以设置为多个,势必会增加处理的效率,但是若是长时间不消费(不进行处理)也是会产生问题,所以这里综合考量 选择处置数量为1,可以在秒杀业务中对数据进行快速的处理。
#\u6D88\u8D39\u8005\u81EA\u52A8\u542F\u52A8
spring.rabbitmq.listener.simple.auto-startup=true
# morn开启
#\u6D88\u8D39\u5931\u8D25\uFF0C\u81EA\u52A8\u91CD\u65B0\u5165\u961F
spring.rabbitmq.listener.simple.default-requeue-rejected= true
# 消费者消费失败以后,会重新将数据压入到队列中
#\u542F\u7528\u53D1\u9001\u91CD\u8BD5
spring.rabbitmq.template.retry.enabled=true 
# 重试确定
spring.rabbitmq.template.retry.initial-interval=1000 
# 一秒
spring.rabbitmq.template.retry.max-attempts=3
# 最多重试次数
spring.rabbitmq.template.retry.max-interval=10000
# 最大的间隔是10s
spring.rabbitmq.template.retry.multiplier=1.0
# 以上只是对当前项目所需进行一个简单配置文件配置有具体需求小伙伴可以查看官网配置

若是yml配置文件如下,具体的每一个字段的含义在上面的配置中有写到:

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    listener:
      simple:
        concurrency: 10
        max-concurrency: 10
        prefetch: 1
        auto-startup: true
        default-requeue-rejected: true
    template:
      retry:
        enabled: true
        initial-interval: 1000
        max-attempts: 3
        max-interval: 10000
        multiplier: 1.0

Rabbitmq交换机

对于Rabbitmq的交换机来说具体的几种模式这里我也是学习别人,这里贴出别人大佬的地址Rabbitmq交换机学习这里就不进行具体的讲解了,下面开始具体部分实例学习:

Direct 模式

对于direct模式也是最简单的模式,就是先行创建一个队列。生产者发送消息,消费者通过队列的名称与生产者建立关联。
首先我们来创建一个config配置文件:

@Configuration
public class MQConfig {
   
public  static  final  String QUEUE="queue";
    @Bean
    public Queue queue(){
   
        return  new Queue(QUEUE,true);
    }
}

然后创建生产者,我们已经成功的进行了pom依赖的引入和连接到本地的rabbitmq服务器上,就可以使用到AmqpTemplate使用注入的方式。

@Service
public class MQSend {
   
    private  static Logger logger= LoggerFactory.getLogger(MQConfig.class);
    // 控制台进行打印
    @Autowired
    AmqpTemplate amqpTemplate;
    public void send (Object message){
   
        String msg= RedisService.beanToString(message);
        // redis的将对象类型转为string类型
        logger.info("send Message:"+msg);
        amqpTemplate.convertAndSend(MQConfig.QUEUE,msg);
        // 调用方法,提供队列名称,和想要发送的消息。
    }
}

生成者创建完成创建消费者:


@Service
public class MQReceiver {
   

    private  static Logger logger= LoggerFactory.getLogger(MQConfig.class);
    //控制台打印
    @RabbitListener(queues = MQConfig.QUEUE)
    // 添加监听的注解,表示监听这个队列
    public  void receiver(String message){
   
        logger.info("receive Message:"+message);
    }
}

以上完成以后我们在Controller中进行调用

//注入调用
@Autowired
    MQSend mqSend;

    @RequestMapping("/mq")
    @ResponseBody
    public Result<String> mq() {
   
        mqSend.send("hello world");
        return Result.success("Hello world");
    }
测试

如下图所示,访问此地址,就可以调用我们的的send()方法:
在这里插入图片描述
因为我们在控制台打印了输出信息,进行查看:发现对于生成者发送的消息对于接收端也真的进行到了接受并正确打印出信息。
在这里插入图片描述

Topic 模式

对于Topic模式还是和Direct模式有部分的区别:

  1. 首先我们还是创建两个queue
  2. 对于Topic模式需要创建一个交换机。
  3. 利用key值将交换机和Queue进行一个绑定。
   @Bean
    public Queue topicQueue1(){
   
        return  new Queue(TOPIC_QUEUE1,true);
    }
    @Bean
    public Queue topicQueue2(){
   
        return  new Queue(TOPIC_QUEUE2,true);
    }
    // 创建交换机
    @Bean
    public TopicExchange topicExchange(){
   
        return new  TopicExchange(TOPIC_EXCHANGE);
    }
    // 创建一个绑定,将队列一与交换机进行一个绑定。key值是 topic.key1。
    @Bean
    public Binding topicBind1(){
   
        return BindingBuilder.bind(topicQueue1()).to(topicExchange()).with("topic.key1");
    }
    // 创建第二个绑定,将队列二与交换机进行一个绑定 key值是topic.# 
    //# 表示通配符匹配,对于任意的topic.XX 都可以进行一个匹配。
    @Bean
    public Binding topicBind2(){
   
        return BindingBuilder.bind(topicQueue2
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值