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客户端会出现连接超时的情况。


相关实践学习
基于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
相关文章
|
14天前
|
缓存 NoSQL Redis
Redis经典问题:数据并发竞争
数据并发竞争是大流量系统(如火车票系统、微博平台)中常见的问题,可能导致用户体验下降甚至系统崩溃。本文介绍了两种解决方案:1) 加写回操作加互斥锁,查询失败快速返回默认值;2) 保持多个缓存备份,减少并发竞争概率。通过实践案例展示,成功提高了系统的稳定性和性能。
|
2月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
14天前
|
存储 NoSQL 网络协议
Redis性能攻略:Redis-benchmark工具与实用性能优化技巧
Redis 是一种高性能的内存数据库,广泛应用于各种业务场景。随着业务规模扩大和数据量增长,性能问题逐渐凸显。本文深入探讨 Redis 性能优化方案,包括硬件配置(网络、内存优化)、参数配置(maxmemory、timeout 等)、数据结构选择、过期策略、持久化机制(RDB、AOF)及集群方案(主从复制、哨兵模式、集群模式),帮助提升 Redis 的整体性能表现。
30 0
|
3月前
|
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时可能遇到的问题和解决方案。
166 1
redis学习四、可视化操作工具链接 centos redis,付费Redis Desktop Manager和免费Another Redis DeskTop Manager下载、安装
|
4月前
|
NoSQL Linux Redis
linux安装单机版redis详细步骤,及python连接redis案例
这篇文章提供了在Linux系统中安装单机版Redis的详细步骤,并展示了如何配置Redis为systemctl启动,以及使用Python连接Redis进行数据操作的案例。
100 2
|
3月前
|
消息中间件 NoSQL Kafka
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
大数据-116 - Flink DataStream Sink 原理、概念、常见Sink类型 配置与使用 附带案例1:消费Kafka写到Redis
214 0
|
5月前
|
存储 NoSQL Redis
【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)
【Azure Developer】一个复制Redis Key到另一个Redis服务的工具(redis_copy_net8)
|
5月前
|
NoSQL 数据可视化 Linux
2022 年超详细步骤讲解 CentOS 7 安装Redis 。解决Redis Desktop Manager 图形化工具连接失败解决 ;connection failed处理。开机自启Redis
这篇文章提供了在CentOS 7上安装Redis的详细步骤,包括上传Redis安装包、解压安装、编译、安装、备份配置文件、修改配置以支持后台运行和设置密码、启动Redis服务、使用客户端连接Redis、关闭Redis服务、解决Redis Desktop Manager图形化工具连接失败的问题、设置Redis开机自启动,以及Redis服务的启动和停止命令。
2022 年超详细步骤讲解 CentOS 7 安装Redis 。解决Redis Desktop Manager 图形化工具连接失败解决 ;connection failed处理。开机自启Redis
|
5月前
|
存储 监控 NoSQL
揭秘Redis慢查询:这个工具将彻底改变你的性能优化策略!
【8月更文挑战第8天】在互联网应用中,数据库性能常成瓶颈。Redis作为高速内存数据库亦可能遭遇慢查询问题。本文探讨慢查询成因与解决方法。首先定义慢查询及其影响因素,随后介绍Redis内置的慢查询日志功能,通过配置`slowlog-log-slower-than`与`slowlog-max-len`来监控执行时间过长的命令。利用`SLOWLOG get`命令分析日志,定位性能瓶颈所在。以`LRANGE`命令为例,提出数据结构调整、使用流水线、限制返回元素数量、异步执行及优化内存使用等策略。最终实现Redis性能提升,确保应用流畅运行。性能优化需持续监控、分析与调整。
143 1
|
6月前
|
NoSQL 算法 Java
(十三)全面理解并发编程之分布式架构下Redis、ZK分布式锁的前世今生
本文探讨了从单体架构下的锁机制到分布式架构下的线程安全问题,并详细分析了分布式锁的实现原理和过程。
122 6