一起聊聊Redis实现秒杀的问题

2022-05-30 0 437

本篇文章给大家带来了关于Redis的相关知识,其中主要介绍了关于实现秒杀的相关内容,包括了秒杀逻辑、存在的链接超时、超卖和库存遗留的问题,下面一起来看一下,希望对大家有帮助。

一起聊聊Redis实现秒杀的问题

推荐学习:Redis视频教程

1、秒杀逻辑

秒杀:解决计数器和人员记录的事务操作

1.uid和proid非空判断2.连接redis3.拼接key库存key秒杀成功用户key4.获取库存,如果库存为null,秒杀还没开始5.判断用户是否重复秒杀操作6.判断商品数量,库存数量小于1,秒杀结束7.秒杀过程库存-1把秒杀成功用户添加清单里面

2、存在问题

2.1、连接超时

原因:由于大量创建连接,十分消耗性能,并且有时获取连接不及时,出现连接超时的情况

2.2、超卖

在并发的情况下发生的,就是在输出没有库存(秒杀结束)后还有商品售出导致库存数量为负数。
一起聊聊Redis实现秒杀的问题

2.3、库存遗留

使用乐观锁解决问题2之后,出现问题3

如果库存数量相对并发更多,由于使用乐观锁,第一个用户秒杀成功后会修改库存键的版本号,其他抢到的用户会因为版本号不同导致无法继续购买,就会有库存遗留问题

3、解决

3.1、连接超时

使用连接池,工具类如下:

public class JedisPoolUtil {private static volatile JedisPool jedisPool = null;private JedisPoolUtil() {}public static JedisPool getJedisPoolInstance() {if (null == jedisPool) {synchronized (JedisPoolUtil.class) {if (null == jedisPool) {JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxTotal(200);poolConfig.setMaxIdle(32);poolConfig.setMaxWaitMillis(100 * 1000);poolConfig.setBlockWhenExhausted(true);poolConfig.setTestOnBorrow(true);jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379, 60000);}}}return jedisPool;}}//使用JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();Jedis jedis = jedisPoolInstance.getResource();

springBoot版本(pom.xml引入,application.yml配置,然后注入对象即可)

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency>    <groupId>redis.clients</groupId>    <artifactId>jedis</artifactId>    <version>3.2.0</version></dependency>
spring:  redis:    host: 127.0.0.1    port: 6379    database: 0    timeout: 1800000    lettuce:      pool:        max-active: 20        max-wait: -1        max-idle: 5        min-idle: 0
    @Autowired    private RedisTemplate redisTemplate;

3.2、超卖问题

使用Redis事务,乐观锁 + watch

//监视库存jedis.watch(kcKey);//中间代码忽略//7 秒杀过程//使用事务Transaction multi = jedis.multi();//组队操作multi.decr(kcKey);multi.sadd(userKey,uid);//执行List<Object> results = multi.exec();if(results == null || results.size()==0) {    System.out.println("秒杀失败了....");    jedis.close();    return false;}

3.3、乐观锁导致的库存遗留问题

使用Lua嵌入式脚本语言

将复杂的或者多步的 Redis 操作,写为一个脚本,一次提交给Redis运行,减少反复连接 reids的次数。提升性能。LUA脚本是类似 redis 事务,有一定的原子性,不会被其他命令插队,可以完成redis事务性的操作LUA脚本功能,在Redis 2.6以上的版本才可以使用利用 lua 脚本淘汰用户,解决超卖问题。redis 2.6 版本以后,通过 lua 脚本解决争抢问题,实际上是 redis 利用其单线程的特性,用任务队列的方式解决多任务并发问题

local userid=KEYS[1];//1、2行定义两个变量,local prodid=KEYS[2];local qtkey="sk:"..prodid..":qt";//3,4行定义拼接keylocal usersKey="sk:"..prodid..":usr";local userExists=redis.call("sismember",usersKey,userid); //5-8,判断用户是否存在,不存在return 2if tonumber(userExists)==1 then    return2;endlocal num=redis.call("get",qtkey);//9-11,判断商品是否存在if tonumber(num)<=0 then    return 0;else//12-15,用户和商品操作    redis.call("decr",qtkey);    redis.call("sadd",usersKey,userid);endreturn1;  //最后一行return 1;  秒杀成功

完整代码如下:

// 定义两段Lua脚本(使用Lua脚本可以解决乐观锁带来的库存遗留问题)static String secKillScript ="local userid=KEYS[1];\\r\\n" +"local prodid=KEYS[2];\\r\\n" +"local qtkey='sk:'..prodid..\\":qt\\";\\r\\n" +"local usersKey='sk:'..prodid..\\":usr\\";\\r\\n" +"local userExists=redis.call(\\"sismember\\",usersKey,userid);\\r\\n" +"if tonumber(userExists)==1 then \\r\\n" +"   return 2;\\r\\n" +"end\\r\\n" +"local num= redis.call(\\"get\\" ,qtkey);\\r\\n" +"if tonumber(num)<=0 then \\r\\n" +"   return 0;\\r\\n" +"else \\r\\n" +"   redis.call(\\"decr\\",qtkey);\\r\\n" +"   redis.call(\\"sadd\\",usersKey,userid);\\r\\n" +"end\\r\\n" +"return 1" ;  public static boolean doSecKill(String uid,String prodid) throws IOException { JedisPool jedispool =  JedisPoolUtil.getJedisPoolInstance();Jedis jedis=jedispool.getResource();jedis.select(2); // 通过jedis的scriptLoad方法加载Lua脚本String sha1=  jedis.scriptLoad(secKillScript);//通过jedis的evalsha方法调用Lua脚本Object result= jedis.evalsha(sha1, 2, uid,prodid); String reString=String.valueOf(result);if ("0".equals( reString )  ) {System.err.println("已抢空!!");}else if("1".equals( reString )  )  {System.out.println("抢购成功!!!!");}else if("2".equals( reString )  )  {System.err.println("该用户已抢过!!");}else{System.err.println("抢购异常!!");}jedis.close();return true;}

推荐学习:Redis视频教程

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

【声明:根据2013年1月30日《计算机软件保护条例》2次修订第17条规定: 为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存 储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬! 鉴于此,也希望大家按此说明研究软件!】
本站所有源码尽量保证原汁原味,如有特殊情况会作出声明及标注,网站资源不做任何二次加密(原版加密除外,不影响程序使用的不会做解密处理),方便您更好的学习参考。 在您的能力范围内,为了大环境的良性发展,请尽可能的选择正版资源。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

即刻码站__国内靠谱的站长资源下载平台 php教程 一起聊聊Redis实现秒杀的问题 https://www.jike1995.com/37687.html

%title缩略图
上一篇: centos6.5支持uefi吗
%title缩略图
下一篇: centos中自带vim吗
常见问题
  • 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度
查看详情

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务