Redis(二十二)-秒杀案例的基本实现以及用ab工具模拟并发

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 上一篇文章我们介绍了悲观锁和乐观锁,Redis(二十一)-Redis的事务冲突(悲观锁和乐观锁)。这篇文章我们接着来学习Redis,本文主要介绍如何通过Redis来实现秒杀,以及如何通过ab工具来模拟并发。

简介

上一篇文章我们介绍了悲观锁和乐观锁,Redis(二十一)-Redis的事务冲突(悲观锁和乐观锁)。这篇文章我们接着来学习Redis,本文主要介绍如何通过Redis来实现秒杀,以及如何通过ab工具来模拟并发。

秒杀案例的基本实现

商品秒杀是电商系统中的一个常见场景,就是商家将拿出少量某商品以特价的方式,在有限的时间内进行销售。在秒杀的场景中需要注意的情况是:1. 商品不能超卖,2. 同一个人只能抢一次。所以,

秒杀的基本实现思路有如下七个步骤:

//uid 是用户ID
// prodid 是商品ID
 public boolean doSeckill(String uid, String prodid) {
        // 1.uid和prodid非空判断
        if (StringUtils.isAnyBlank(uid, prodid)) {
            System.out.println("uid和prodid为空");
            return false;
        }
        // 2.连接redis
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        // 3.拼接key
        // 3.1. 库存key
        String skKey = "sk:" + prodid + ":qt";
        // 3.2. 秒杀成功用户key
        String userKey = "sk:" + prodid + ":user";
        // 4.获取库存,如果库存null,秒杀还没有开始
        String skValue = jedis.get(skKey);
        if (skValue == null) {
            System.out.println("秒杀还没开始,请等待");
            jedis.close();
            return false;
        }
        // 5.判断用户是否重复操作
        Boolean sismember = jedis.sismember(userKey, uid);
        if (sismember) {
            System.out.println("该用户已经抢过一次,请勿重复抢购");
            jedis.close();
            return false;
        }
        // 6. 判断如果商品数量,库存数量小于1,秒杀结束
        if (Integer.parseInt(skValue) <= 0) {
            System.out.println("该商品的库存不足,秒杀失败");
            jedis.close();
            return false;
        }
        // 7. 秒杀过程
        //    7.1. 库存-1
        jedis.decr(skKey);
        //    7.2. 用户加入到set集合中
        jedis.sadd(userKey, uid);
        System.out.println("秒杀成功");
        return true;
    }

为了防止某个用户重复抢,所以需要将抢过的用户id放在set 这个数据类型中,在每次请求是需要判断该set中有没有该用户。

为了防止超卖的情况,所以,在每次请求之前都需要查看一下当前的商品数量,如果商品数量等于0则返回库存不足,用户成功抢到商品之后需要将库存-1。

定义的测试接口是:

 

@RequestMapping("/skill/do")
    public boolean setandGetValue() {
        String prodid = "1010";
        StringBuilder uidSB = new StringBuilder("");
        for (int i = 0; i < 6; i++) {
            int nextInt = new Random().nextInt(10);
            uidSB.append(nextInt);
        }
        boolean result = seckillService.doSeckill(uidSB.toString(), prodid);
        return result;
    }

在redis中设置秒杀商品的数量为10个。设置的命令是:set sk:1010:qt 10

8dcc031d56a949220effa82a01a860de_ab650f80ce544c8ea3a10ce749bb0a97.png

请求地址是:http://10.41.152.17:8080/seckill/skill/do。其中seckill是项目名。单个请求的测试结果如下图所示:

af52706f54c1730cc774581819116832_4b869a80411b4fb3b6f5559a7018da7d.png

ab工具模拟并发

这里通过Linux的ab工具模拟并发测试,ab工具的安装使用非常简单。

安装ab工具

在联网的情况下只需要通过 yum install httpd-tools 命令即可安装ab工具。

安装完成之后通过ab --help 命令可以查看ab命令的各个参数的含义。

其中最常用的参数是:

-n  最大的请求数
-c  同时最大的并发数
-p postfile  指定post请求的参数
-T 指定请求的content-type

可以通过vim postfile 模拟表单提交参数,以&符号结尾,存放在当前目录,输入内容 prodid=1010& (PS: 在本次测试中实际上没有到)

输入下面的测试命令测试一波,该命令指定了最大请求数是1000个,并发数是100个,10.41.152.17 是你本机的IP地址。

ab -n 1000 -c 100 -p postfile -T 'application/x-www-form-urlencoded' http://10.41.152.17:8080/seckill/skill/do

在测试之前依然通过set sk:1010:qt 10 命令设置10个秒杀商品qt。

执行结果如下三个图片所示:


从上述两个图片可以看出此基本实现过程有如下几个问题:

前面的线程都提示 商品库存不足,秒杀失败,后面的线程还能提示 秒杀成功,检查商品的数量发现商品数量为-6,也就是说出现了超卖的情况。

5cf784c28203f62569c514b3aa97f41b_d3a2cb5a95d64fd8a6f580e9071dfee9.png

后面的jedis客户端请求会出现 connect timed out 连接超时的情况。

这两个问题的解决方案会在后续的文章中详细介绍。

总结

本文通过jedis客户端简单实现了秒杀的案例,并通过ab工具模拟了并发测试。但是,由于代码设计考虑不周,会出现超卖以及jedis客户端会出现连接超时的情况。


相关文章
|
6月前
|
存储 NoSQL Redis
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构
|
7月前
|
NoSQL 关系型数据库 MongoDB
接口管理工具深度对比:Apipost与Apifox在Redis/MongoDB支持上的关键差异
近期在团队工具选型时,系统对比了Apifox和Apipost两款接口管理工具,我们的体会是:Apipost适合需要同时管理多种数据库的中大型项目,特别是涉及Redis/MongoDB等非关系型数据库的场景,Apifox仅建议在纯关系型数据库架构且预算有限的小型项目中短期使用。
197 3
|
9月前
|
JSON NoSQL Java
从Redis到Tair:开源工具的最佳实践
《从Redis到Tair:开源工具的最佳实践》介绍了Redis闭源后Valkey社区的成立及其兼容性测试、性能测试、数据迁移与校验、客户端接入最佳实践,以及Tair的开源模块。内容涵盖Redis闭源背景、阿里云在Valkey社区中的贡献、Tair与Redis的兼容性测试工具(如resp-compatibility)、性能测试工具(如RESP-Benchmark)、数据迁移工具(如Redis Shake)及数据校验工具。此外,还详细介绍了TairHash和TairDoc两个开源模块的应用场景,帮助用户更好地理解和使用这些工具。
406 4
|
11月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
10月前
|
缓存 NoSQL Redis
Redis经典问题:数据并发竞争
数据并发竞争是大流量系统(如火车票系统、微博平台)中常见的问题,可能导致用户体验下降甚至系统崩溃。本文介绍了两种解决方案:1) 加写回操作加互斥锁,查询失败快速返回默认值;2) 保持多个缓存备份,减少并发竞争概率。通过实践案例展示,成功提高了系统的稳定性和性能。
|
12月前
|
NoSQL 数据可视化 Linux
redis学习四、可视化操作工具链接 centos redis,付费Redis Desktop Manager和免费Another Redis DeskTop Manager下载、安装
本文介绍了Redis的两个可视化管理工具:付费的Redis Desktop Manager和免费的Another Redis DeskTop Manager,包括它们的下载、安装和使用方法,以及在使用Another Redis DeskTop Manager连接Redis时可能遇到的问题和解决方案。
1325 1
redis学习四、可视化操作工具链接 centos redis,付费Redis Desktop Manager和免费Another Redis DeskTop Manager下载、安装
|
10月前
|
存储 NoSQL 网络协议
Redis性能攻略:Redis-benchmark工具与实用性能优化技巧
Redis 是一种高性能的内存数据库,广泛应用于各种业务场景。随着业务规模扩大和数据量增长,性能问题逐渐凸显。本文深入探讨 Redis 性能优化方案,包括硬件配置(网络、内存优化)、参数配置(maxmemory、timeout 等)、数据结构选择、过期策略、持久化机制(RDB、AOF)及集群方案(主从复制、哨兵模式、集群模式),帮助提升 Redis 的整体性能表现。
427 0
|
NoSQL Linux Redis
linux安装单机版redis详细步骤,及python连接redis案例
这篇文章提供了在Linux系统中安装单机版Redis的详细步骤,并展示了如何配置Redis为systemctl启动,以及使用Python连接Redis进行数据操作的案例。
305 3
|
12月前
|
消息中间件 NoSQL Kafka
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
717 0
|
存储 NoSQL Redis
【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)
【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)
【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)