Redis中秒杀场景下超时与超卖问题如何解决
超时1.redis连接超时原因
(1)虚拟机中的配置问题
我们在测试远程连接时redis连接是否成功时控制台可能会报以下错误。如下所示:
每次看到控制台红色的文字我就头疼。。。
在控制台中的显示大概意思是显示连接超时导致了失败。总结了以下三条连接失败原因:
Linux中的防火墙没有关闭而导致失败。
redis要打开。
redis.conf中的bind 127.0.01需要注释掉,然后 需要修改protected-mode no。
之后如果遇到了以上问题请自行查找。
(2)redis成功连接中模拟在高并发中的超时
如图所示:
2.解决方法在MySQL中使用jdbc可能会发现连接超时问题,所以我们使用了数据库连接池来解决问题,例如druid、c3p0等等。同理我们在redis中也可以同样使用数据库连接池。节省每次连接redis服务带来的消耗,把连接好的实例反复利用。
通过参数管理连接的行为
直接上记事本代码!
链接池参数:
MaxTotal:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了MaxTotal个jedis实例,则此时pool的状态为exhausted。
maxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
MaxWaitMillis:表示当borrow一个jedis实例时,最大的等待毫秒数,如果超过等待时间,则直接抛JedisConnectionException;
testOnBorrow:获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;
在高并发场景下,多个线程并发更新库存,导致库存为负的情况。
看图幻想:
2.解决方案(1)利用乐观锁淘汰用户,解决超卖问题上图:
//增加乐观锁jedis.watch(qtkey);
//3.判断库存
String qtkeystr = jedis.get(qtkey);
if(qtkeystr==null || "
"
.equals(qtkeystr.trim())) {
System.out.println("
未初始化库存"
);
jedis.close();
return false ;
}
int qt = Integer.parseInt(qtkeystr);
if(qt<
=0) {
System.err.println("
已经秒光"
);
jedis.close();
return false;
}
//增加事务
Transaction multi = jedis.multi();
//4.减少库存
//jedis.decr(qtkey);
multi.decr(qtkey);
//5.加人
//jedis.sadd(usrkey, uid);
multi.sadd(usrkey, uid);
//执行事务
List<
Object>
list = multi.exec();
//判断事务提交是否失败
if(list==null || list.size()==0) {
System.out.println("
秒杀失败"
);
jedis.close();
return false;
}
System.err.println("
秒杀成功"
);
jedis.close();
方案原理:
(1)当用户购买时,通过watch来监视库存,如果库存在watch监视后发生改变,就会捕获异常而放弃对库存进行减一操作。(2)如果库存没有监视到变化并且数量大于一时,则库存减一,并且执行任务。弊端
Redis 在尝试完成一个事务的时候,可能会因为事务的失败而重复尝试重新执行保证商品的库存量正确是一件很重要的事情,但是单纯的使用 WATCH 这样的机制对服务器压力过大
(2)、使用reids的 watch + multi + setnx 指令实现为什么要自己构建锁?
虽然有类似的 SETNX 命令可以实现 Redis 中的锁的功能,但他锁提供的机制并不完整并且setnx也不具备分布式锁的一些高级特性,还是得通过我们手动构建。
(1)创建一个redis锁
在 Redis 中,可以通过使用 SETNX 命令来构建锁:rs.setnx(lock_name, uuid值)而锁要做的事情就是将一个随机生成的 128 位 UUID 设置位键的值,防止该锁被其他进程获取。
(2)释放锁
锁的删除操作很简单,只需要将对应锁的 key 值获取到的 uuid 结果进行判断验证符合条件(判断uuid值)通过 delete 在 redis 中删除即可,rs.delete(lockname)此外当其他用户持有同名锁时,由于 uuid 的不同,经过验证后不会错误释放掉别人的锁.
(3)解决锁无法释放问题
在之前的锁中,还出现这样的问题,比如某个进程持有锁之后突然程序崩溃,那么会导致锁无法释放而其他进程无法持有锁继续工作,为了解决这样的问题,可以在获取锁的时候加上锁的超时功能。
如今,秒杀活动已成为众多电商平台的必备营销手段。在这一场景下,Redis作为流行的高性能内存数据库,也成为了解决秒杀超时与超卖问题的重要工具。本文将深入探讨这两个问题以及Redis提供的解决方案。
解决超时问题:借助Redis的过期时间
在秒杀场景中,用户与库存之间的竞争是非常激烈的。因此,在用户获取秒杀商品的过程中,会存在超时的情况。这个问题可以通过Redis的过期时间解决。在秒杀开始前,将秒杀商品的库存数量存放在Redis中,并设置一个过期时间。当用户申请获取商品时,先检查库存数量是否为0。如果不为0,则将库存数量减1,并返回商品信息。如果为0,则表示秒杀商品已全部售罄,用户无法获取商品。
解决超卖问题:利用Redis的事务特性
超卖是秒杀场景中必须解决的主要问题之一。将库存数量存放在Redis中,虽然可以在并发情况下保证库存的准确性,但并不能保证在高并发情况下不会出现超卖问题。这个问题可以通过Redis的事务特性解决。在用户申请获取秒杀商品时,首先将Redis中的库存数量取出,并启动一个事务。然后,在事务中对库存数量进行减1操作,并将处理结果返回给用户。如果库存数量不足,则撤销事务。通过这种方式,可在高并发情况下避免超卖问题的出现。
总结:Redis优化秒杀场景中的性能问题
在秒杀场景下,利用Redis解决超时与超卖问题是必不可少的。通过Redis的过期时间和事务特性,可实现高并发情况下的性能优化。此外,在使用Redis时,还要充分考虑到Redis的内存限制、持久化方式和配置优化等方面的问题。只有在全面优化的前提下,才能真正实现秒杀场景的高性能和稳定性。