Redis:抢单预热

前言

在当今的互联网时代,抢单活动已经成为了电商平台、外卖平台等各种电子商务平台中常见的营销手段。通过抢单活动,商家可以吸引大量用户参与,从而提高销量和知名度。然而,抢单活动所带来的高并发请求往往会给系统带来巨大的压力,如何在抢单活动开始前进行预热,以确保系统能够稳定运行,成为了技术人员需要解决的重要问题。

在这篇博客中,我们将深入探讨如何利用Redis技术来进行抢单预热,以应对抢单活动带来的高并发访问压力。我们将介绍Redis的基本概念和特点,以及如何利用Redis来进行缓存预热、数据预加载等操作,从而提高系统的并发处理能力和稳定性。同时,我们也将分享一些实际案例和经验,帮助读者更好地理解和应用Redis技术解决抢单预热的挑战。

通过本文的学习,读者将能够深入了解抢单预热的必要性和原理,掌握利用Redis进行抢单预热的具体方法和技巧,从而为自己的系统应对抢单活动带来的高并发访问压力提供有效的解决方案。让我们一起深入探讨Redis在抢单预热中的应用吧!

一、前期准备

1、新建项目,结构如下

 2、添加依赖
<dependencies>
        <!-- 放在最前面依赖,依据依赖的最短路径原则,
             将不在使用spring-data中的slf4j,否则
             会引发冲突-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.3.8</version>
        </dependency>

        <!-- spring data框架,提供了对redis的整合支持,
             内部支持lettuce以及Jedis客户端-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.5.6</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.29</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.29</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.3.29</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>

        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>6.2.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.11.2</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.6</version>
        </dependency>
    </dependencies>

这个Maven项目中包含了多个依赖,以下是每个依赖的作用:

  1. logback-classic: 这是logback日志框架的经典模块,用于在应用程序中进行日志记录和管理。

  2. spring-data-redis: 提供了Spring Data框架对Redis的整合支持,包括对lettuce和Jedis客户端的支持,可以方便地使用Redis进行数据操作。

  3. javax.servlet-api: 这是Java Servlet API的依赖,提供了对Servlet的支持,通常在Java Web应用中使用。

  4. spring-webmvc: Spring框架的Web MVC模块,提供了基于MVC架构的Web应用程序开发支持。

  5. spring-jdbc: Spring框架的JDBC模块,提供了对JDBC的封装和支持,用于在Spring应用中进行数据库操作。

  6. spring-tx: Spring框架的事务管理模块,提供了声明式事务管理的支持。

  7. druid: 阿里巴巴开源的数据库连接池,在应用中用于管理数据库连接。

  8. mysql-connector-java: MySQL数据库的JDBC驱动,用于连接MySQL数据库。

  9. lettuce-core: Lettuce是一个高性能的开源Java Redis客户端,用于与Redis进行交互。

  10. lombok: Lombok是一个Java库,可以通过注解的方式来简化Java代码的编写,提高开发效率。

  11. junit: JUnit是一个Java单元测试框架,用于编写和运行自动化的单元测试。

  12. jackson-databind: Jackson是一个流行的Java JSON处理库,jackson-databind模块提供了数据绑定功能,用于将Java对象和JSON数据进行相互转换。

  13. mybatis: MyBatis是一个持久层框架,用于在Java应用中进行数据库操作。

  14. mybatis-spring: MyBatis与Spring框架的整合模块,提供了MyBatis和Spring框架的无缝集成支持。

这些依赖项涵盖了日志记录、Web开发、数据库操作、缓存操作、测试等多个方面,可以满足一个典型的Java应用程序的开发需求。

二、编写 dao

由于代码量太多了,就不一一讲解了,本次案例只是讲重要的怎么预热和减库存。 

1、GoodsDao
public interface GoodsDao {

    /**
     * 查询参与活动的商品
     * @return
     */
    List<Goods> listProduct();

    /**
     * 减库存
     * @param id
     * @return
     */
    void decrStock(int id);
}

首先要有一个查询库存的方法和一个删减库存的方法。 

三、编写 service

1、OrderService
public interface OrderService {
    /**
     * 下单
     * @param id
     */
    void placeOrder(int id);
}

 当库存放生改变时,我们需要为这写下单的用户添加订单记录。

2、GoodsService
public interface GoodsService {

    /**
     * 扣减库存
     * @param id
     */
    void decrStock(int id);
}

当下单成功后,需要扣减数据库的库存数量。

3、GoodsServiceImpl
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional(rollbackFor = RuntimeException.class)
public class GoodsServiceImpl implements GoodsService {

    private final GoodsDao goodsDao;

    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 缓存预热
     */
    @PostConstruct
    public void initProductCache() {
        goodsDao.listProduct().forEach(goods -> {
            //将商品数量加入redis缓存
            String key = GoodsEnum.PREFIX.value() + goods.getId();
            redisTemplate.opsForValue().set(key, goods.getStock(), Duration.ofMinutes(60));
        });
    }

    @Override
    public void decrStock(int id) {
        goodsDao.decrStock(id);
    }
}

这段代码是一个名为GoodsServiceImpl的服务类,使用了Lombok的@RequiredArgsConstructor注解来自动生成构造函数,并且使用了Slf4j来实现日志记录。同时,@Service注解表明这是一个Spring的服务类,@Transactional注解表明这个类中的方法将进行事务管理,并且在遇到RuntimeException时进行回滚。

这个类中有两个成员变量:GoodsDao和RedisTemplate。GoodsDao是一个数据访问对象,用于对商品数据进行持久化操作;而RedisTemplate是Spring提供的用于操作Redis的模板类。

在这个类中,有一个@PostConstruct注解的方法initProductCache(),它在类实例化后会被自动调用。这个方法通过goodsDao.listProduct()获取所有商品,并将它们的库存数量加入到Redis缓存中,以实现商品的缓存预热。对于每个商品,它会将商品的id作为key,库存数量作为value存入Redis,并设置了缓存的有效期为60分钟。

另外,这个类还实现了GoodsService接口,其中包含了decrStock(int id)方法,用于减少商品库存。在这个方法中,它调用了goodsDao.decrStock(id)来实现对商品库存的减少操作。

总的来说,这个类主要负责商品库存的管理,通过缓存预热来提高系统性能,并且在减少商品库存时进行事务管理。

4、OrderServiceImpl

@Service
@Slf4j
@RequiredArgsConstructor
@Transactional
public class OrderServiceImpl implements OrderService {

    private final RedisTemplate<String, Object> redisTemplate;

    private final OrderDao orderDao;

    private final GoodsDao goodsDao;

    /**
     * 下单
     * @param id
     */
    @Override
    public void placeOrder(int id) {
        //扣减库存
        decrCacheStock(id);
        //生成订单
        createOrder(id);
        //同步数据库的库存
        goodsDao.decrStock(id);
    }

    /**
     * 在缓存中扣减库存
     * @param id
     */
    private void decrCacheStock(int id) {
        //扣减库存(原子减),并返回剩余库存量
        long stock = redisTemplate.opsForValue().decrement(GoodsEnum.PREFIX.value() + id);
        //如果redis中库存为0,则抛出异常告诉用户已经售罄
        if(stock < 0) {
            //在并发时redis扣减后的库存为负数,因此要将redis自增回来
            redisTemplate.opsForValue().increment(GoodsEnum.PREFIX.value() + id);
            throw new OrderException(ErrorMessageEnum.SELL_OUT);
        }
    }

    /**
     * 生成订单
     * @param gid
     */
    private Order createOrder(int gid) {
        try {
            Order order = new Order();
            //用户ID
            order.setUserId(1);
            //商品ID
            order.setGoodsId(gid);
            //0表示未支付
            order.setStatus(0);
            orderDao.save(order);
            return order;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }
}

 这段代码是一个名为OrderServiceImpl的服务类,同样使用了Lombok的@RequiredArgsConstructor注解来自动生成构造函数,并且使用了@Slf4j来实现日志记录。同时,@Service注解表明这是一个Spring的服务类,@Transactional注解表明这个类中的方法将进行事务管理。

这个类中有三个成员变量:RedisTemplate用于操作Redis缓存,OrderDao用于对订单数据进行持久化操作,GoodsDao用于对商品数据进行持久化操作。

在这个类中,有一个placeOrder(int id)方法,用于处理下单操作。在这个方法中,首先调用了decrCacheStock(int id)方法来扣减商品的库存,然后调用了createOrder(int id)方法来生成订单,最后调用了goodsDao.decrStock(id)方法来同步数据库中的库存信息。

在decrCacheStock(int id)方法中,它使用了RedisTemplate来实现对Redis缓存中商品库存的扣减操作,并且通过判断库存是否小于0来判断商品是否售罄,如果售罄则抛出OrderException异常。

在createOrder(int gid)方法中,它创建了一个订单对象,并将订单信息存入数据库中。如果在存入数据库时出现异常,它会记录错误日志并抛出RuntimeException异常。

总的来说,这个类主要负责处理订单的生成和库存的扣减操作,通过调用RedisTemplate来实现对Redis缓存的操作,并且在数据库操作时进行事务管理。

 

四、编写controller

@RestController
@RequiredArgsConstructor
public class OrderController extends BaseController{

    private final OrderService orderService;

    @PostMapping("/seckill")
    public ResultVO placeOrder(Integer gid) {
        orderService.placeOrder(2);
        return success();
    }
}

这段代码是一个名为OrderController的控制器类,使用了Lombok的@RequiredArgsConstructor注解来自动生成构造函数,并且继承了BaseController。同时,@RestController注解表明这是一个Spring的RESTful控制器类。

在这个类中,有一个成员变量OrderService,用于处理订单相关的业务逻辑。在控制器中,有一个@PostMapping注解的方法placeOrder(Integer gid),用于处理秒杀下单的请求。在这个方法中,它调用了orderService.placeOrder(2)来处理下单操作,并且返回了一个ResultVO对象,通过success()方法来表示操作成功。

总的来说,这个控制器类主要用于处理秒杀下单的请求,通过调用OrderService来实现下单操作,并返回相应的结果。

 五、使用jmeter测试

官网网址:Apache JMeter - Apache JMeter™

去官网下载下来,我们用 jmeter 来测试我们的controller。

 1、jmeter有什么用

JMeter是一个用于进行性能测试的开源工具,它最初是为测试Web应用程序而设计的,但后来扩展到其他测试领域。JMeter的主要用途包括:

  1. 性能测试:JMeter可以模拟多个并发用户对目标系统(如Web服务器、数据库、FTP服务器等)发起请求,以评估系统的性能和稳定性。它可以测量系统在不同负载下的响应时间、吞吐量和并发用户数等指标,帮助开发人员和测试人员发现系统性能方面的问题。

  2. 负载测试:通过模拟大量用户请求,JMeter可以测试系统在高负载情况下的表现,评估系统的承载能力和性能瓶颈,以便确定系统是否能够满足预期的用户需求。负载测试也可以用于验证系统的可伸缩性和稳定性。

  3. 压力测试:JMeter可以模拟系统在正常或异常负载下的表现,以便评估系统在不同压力下的稳定性和可靠性。通过压力测试,可以发现系统在极端情况下可能出现的问题,如内存泄漏、资源竞争等。

  4. 功能测试:除了性能测试,JMeter也可以用于进行功能测试,例如测试网站的登录、注册、搜索等功能,以及测试API的响应等。

总的来说,JMeter是一个功能强大的测试工具,可以帮助开发人员和测试人员进行性能、负载、压力和功能测试,以确保系统能够稳定、高效地运行。

2、测试
1)打开 jmeter ,bin目录下双击ApacheJMeter.jar 运行

运行:

 

 2)添加线程组

3)添加HTTP请求
 
4)添加汇总报告
 
5)填写信息

 添加循环数量,我们的库存中有100个库存,我们执行150次,看会不会出现超卖的情况。还是售完了直接就抛异常。

填写 HTTP 协议

 

请求路径不要写错了,还有就是请求的方式是什么就选择什么。

6)测试结果
 

当运行测试后,售完100个数量之后并没有出现超卖的现象,证明我们的代码就没有写错,并且在售完之后直接提示用户商品已售完。

六、gitee 案例

地址:ch02 · qiuqiu/Redis-study - 码云 - 开源中国 (gitee.com)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

opencv-形态学处理

通过阈值化分割可以得到二值图&#xff0c;但往往会出现图像中物体形态不完整&#xff0c;变的残缺&#xff0c;可以通过形态学处理&#xff0c;使其变得丰满&#xff0c;或者去除掉多余的像素。常用的形态学处理算法包括&#xff1a;腐蚀&#xff0c;膨胀&#xff0c;开运算&a…

Spring-IOC-@Import的用法

1、Car.java package com.atguigu.ioc; import lombok.Data; Data public class Car {private String cname; }2、 MySpringConfiguration2.java package com.atguigu.ioc; import org.springframework.context.annotation.Bean; import org.springframework.context.annotatio…

一、防火墙-基础知识

学习防火墙之前&#xff0c;对路由交换应要有一定的认识 1、什么是防火墙2、防火墙的发展史3、安全区域3.1.接口、网络和安全区域的关系3.2.报文在安全区域之间流动方向3.3.安全区域的配置安全区域小实验 3.4.状态检测和会话机制3.4.1.状态检测3.4.2.会话 3.5.状态检测和会话机…

c语言-数据结构-链式二叉树

目录 1、二叉树的概念及结构 2、二叉树的遍历概念 2.1 二叉树的前序遍历 2.2 二叉树的中序遍历 2.3 二叉树的后序遍历 2.4 二叉树的层序遍历 3、创建一颗二叉树 4、递归方法实现二叉树前、中、后遍历 4.1 实现前序遍历 4.2 实现中序遍历 4.3 实现后序遍历 5、…

《算法通关村——最长公共前缀问题解析》

《算法通关村——最长公共前缀问题解析》 14. 最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow","flight…

腾讯云代金券怎么领取(腾讯云代金券在哪领取)

腾讯云代金券是可抵扣费用的优惠券&#xff0c;领券之后新购、续费、升级腾讯云相关云产品可以直接抵扣订单金额&#xff0c;节省购买腾讯云的费用&#xff0c;本文将详细介绍腾讯云代金券的领取方法和使用教程。 一、腾讯云代金券领取 1、新用户代金券【点此领取】 2、老用户…

Unity中Shader的PBR的基础知识与理论

文章目录 前言一、什么是PBR二、什么是PBS在这里插入图片描述 三、PBS的核心理论1、物质的光学特性&#xff08;Substance Optical Properties&#xff09;2、微平面理论&#xff08;Microfacet Theory&#xff09;3、能量守恒&#xff08;Energy Conservation&#xff09;4、菲…

90%的测试工程师是这样使用Postman做接口测试的...

一&#xff1a;接口测试前准备 接口测试是基于协议的功能黑盒测试&#xff0c;在进行接口测试之前&#xff0c;我们要了解接口的信息&#xff0c;然后才知道怎么来测试一个接口&#xff0c;如何完整的校验接口的响应值。 那么问题来了&#xff0c;那接口信息从哪里获取呢&…

金山云2023年Q3财报:持续向好!

11月21日&#xff0c;金山云公布了2023年第三季度业绩。 财报显示&#xff0c;金山云Q3营收16.3亿元&#xff0c;调整后毛利率达12.1%再创历史新高&#xff0c;调整后毛利额同比上涨57.5%。今年第三季度&#xff0c;公有云实现收入10.2亿元&#xff0c;毛利率达到4.7%&#xf…

STM32出现 Invalid Rom Table 芯片锁死解决方案

出现该现象的原因为板子外部晶振为25M&#xff0c;而程序软件上以8M为输入晶振频率&#xff0c;导致芯片超频锁死&#xff0c;无法连接、下载。 解决方案 断电&#xff0c;将芯片原来通过10k电阻接地的BOOT0引脚直接接3.3V&#xff0c;硬件上置1上电&#xff0c;连接目标板&am…

Redis跳跃表

前言 跳跃表(skiplist)是一种有序数据结构&#xff0c;它通过在每一个节点中维持多个指向其他节点的指针&#xff0c;从而达到快速访问节点的目的。 跳跃表支持平均O(logN)&#xff0c;最坏O(N)&#xff0c;复杂度的节点查找&#xff0c;还可以通过顺序性来批量处理节点…

ROS2中Executors对比和优化

目录 SingleThreadExecutorEventExecutor SingleThreadExecutor 执行流程 EventExecutor 通信图

局域网文件共享神器:Landrop

文章目录 前言解决方案Landrop软件界面手机打开效果 软件操作 前言 平常为了方便传文件&#xff0c;我们都是使用微信或者QQ等聊天软件&#xff0c;互传文件。这样传输有两个问题&#xff1a; 必须登录微信或者QQ聊天软件。手机传电脑还有网页版微信&#xff0c;电脑传手机比…

MT8735/MTK8735安卓核心板规格参数介绍

MT8735核心板是一款高性能的64位Cortex-A53四核处理器&#xff0c;设计用于在4G智能设备上运行安卓操作系统。这款多功能核心板支持LTE-FDD/LTE-TDD/WCDMA/TD-SCDMA/EVDO/CDMA/GSM等多种网络标准&#xff0c;同时还具备WiFi 802.11a/b/g/n和BT4.0LE等无线通信功能。此外&#x…

pipeline传参给job

场景&#xff1a;pipeline实现自动部署&#xff0c;job实现自动测试&#xff0c;但是只有部署dddd环境时&#xff0c;才调自动测试的job&#xff0c;所以需要在调自动测试job时&#xff0c;把参数传给测试job 上一个任务会显示下一步调谁 ------------------------------------…

Redis从入门到精通(三)-高阶篇

文章目录 0. 前言[【高阶篇】3.1 Redis协议(RESP )详解](https://blog.csdn.net/wangshuai6707/article/details/132742584)[【高阶篇】3.3 Redis之底层数据结构简单动态字符串(SDS)详解](https://blog.csdn.net/wangshuai6707/article/details/131101404)[【高阶篇】3.4 Redis…

玩转系统|长亭雷池WAF详细使用教程——深入了解

目录 配置防护站点 界面操作​ 如何配置域名、端口、上游服务器​ 工作原理​ 在单独设备上部署雷池&#xff08;推荐&#xff09;​ 直接在网站服务器上部署雷池​ 和其他反代设备一起部署的情况​ 配置后网站无法访问&#xff0c;如何排查​ 测试防护效果 确认网站…

5-4计算一串字符的空格数字字符其他

#include<stdio.h> int main(){char c;int space0;//空格int letters0;//英文字母int numbers0;//数字int others0;//其他字符printf("请输入一行字符&#xff1a;");while((cgetchar())!\n)//获取字符的内容&#xff0c;到\n停止{if(c>a&&c<z|…

BGP笔记

自治系统----AS AS划分的原因&#xff1a;如果网络太大&#xff0c;路由数量进一步增加&#xff0c;路由表规模变得太大&#xff0c;会导致路由收敛速度变慢&#xff0c;设备性能消耗加大&#xff0c;且全网设备对于路由信息的认知不同&#xff0c;造成流量通讯障碍 AS号&…

智能时代的智能工具(gpt)国产化助手

目前gpt对代码以及其他领域都是可以支持&#xff0c;在国内有很多&#xff0c;常用的百度的 文心一言 &#xff0c;阿里的 通义千问 &#xff0c;还有&#xff08;“豆包”&#xff0c;“”讯飞星火“”&#xff09;等&#xff0c;除了写代码可以外&#xff0c;也可以很好的支持…