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

本文涉及的产品
云数据库 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客户端会出现连接超时的情况。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
NoSQL 数据可视化 关系型数据库
推荐几个好用的redis可视化工具
推荐几个好用的redis可视化工具
180 1
|
1天前
|
NoSQL Linux Redis
Redis内存分析工具RDR
Redis内存分析工具RDR
11 1
|
12天前
|
缓存 NoSQL Java
Redis7的10大应用场景和案例解析
你在项目中使用 Redis 实现了什么应用场景,欢迎一起跟 V 哥讨论。同时也做个小调查,朋多少兄弟是需要了解 Redis 核心源码的,人多的话,下一篇 V 哥写 Redis7的源码分析,人少的话就算了,感谢。
|
2月前
|
存储 监控 NoSQL
【Redis技术专区】「优化案例」谈谈使用Redis慢查询日志以及Redis慢查询分析指南
【Redis技术专区】「优化案例」谈谈使用Redis慢查询日志以及Redis慢查询分析指南
35 0
|
2月前
|
缓存 NoSQL 前端开发
【Redis技术专区】「实战案例」谈谈使用Redis缓存时高效的批量删除的几种方案
【Redis技术专区】「实战案例」谈谈使用Redis缓存时高效的批量删除的几种方案
47 0
|
2月前
|
NoSQL Linux 网络安全
Redis 客户端工具
Redis 客户端工具
26 0
|
2月前
|
缓存 NoSQL Java
Java项目:支持并发的秒杀项目(基于Redis)
Java项目:支持并发的秒杀项目(基于Redis)
38 0
|
2月前
|
NoSQL Java 数据库
优惠券秒杀案例 - CAS、Redis+Lua脚本解决高并发并行
优惠券秒杀案例 - CAS、Redis+Lua脚本解决高并发并行
107 0
|
2月前
|
NoSQL 数据可视化 Unix
一款开源、免费、跨平台的Redis可视化管理工具
一款开源、免费、跨平台的Redis可视化管理工具
|
4月前
|
存储 缓存 NoSQL
《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型
《吊打面试官》系列-Redis双写一致性、并发竞争、线程模型
42 0