Redis中秒杀场景下超时与超卖问题的解决方案

目录
  • 超时
    • 1.redis连接超时原因
    • 2.解决方法
  • 超卖
    • 1.秒杀超卖现象
    • 2.解决方案
      • (1)利用乐观锁淘汰用户,解决超卖问题
      • (2)、使用reids的 watch + multi + setnx 指令实现

在开发过程中高并发问题是很棘手的一个问题(对于博主这样的小菜鸡来说),当我们学习redis之前,知道redis是单线程运行的所以任务不会出现线程不安全问题。当我们在linux中使用ab来模拟高并发秒杀时可能会遇到两种问题,“超时和超卖”。

超时

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实例均是可用的;

超卖

1.秒杀超卖现象

在高并发场景下,多个线程并发更新库存,导致库存为负的情况。

看图幻想:

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 超时与超卖内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Redis高并发场景下秒杀超卖解决方案(秒杀场景)

    目录 1 什么是秒杀 2 为什么要防止超卖 3 单体架构常规秒杀 3.1 常规减库存代码 3.2 模拟高并发 3.3 超卖现象 3.4 分析原因 4 简单实现悲观乐观锁解决单体架构超卖 4.1 悲观锁 4.2 乐观锁 4.3 redis锁setnx 4.4 使用Redision 5 分布式锁的解决方案 6 采用缓存队列防止超卖 1 什么是秒杀 秒杀最直观的定义:在高并发场景下而下单某一个商品,这个过程就叫秒杀 [秒杀场景] 火车票抢票 双十一限购商品 热度高的明星演唱会门票 … 2 为什么要防止

  • Redis分布式锁实现方式及超时问题解决

    一 前言 redis在分布式应用十分广泛,本篇文章也是互联网面试的重点内容,读者至少需要知道为什么需要分布式锁,分布式锁的实现原理,分布式锁的应用场景,在使用分布式锁时遇到哪些问题?你是如何解决的,如果读者能掌握以上问题,那么关于这道面试题,你也就基本过关了: 二 分布式锁的产生背景 分布式锁对应的是多个应用,每个应用中都可能会处理相同的数据,如果多个应用对用一个操作进行了重复操作,就会出现数据不一致,数据重复问题,于是分布式锁应用而生,通常你可以理解为多线程中的synchronized 三 分

  • Redis开启键空间通知实现超时通知的步骤

    Redis部分设置 修改配置文件redis.conf(Windows为redis.windows.conf) 打开该配置文件(位置取决于自己的安装位置),找到Event notification部分. 将notify-keyspace-events Ex的注释打开或者添加该配置,其中E代表Keyevent,此种通知会返回key的名字,x代表超时事件. 如果notify-keyspace-events ""配置没有被注释的话要注释掉,否则不会生效. 保存后重启redis,一定要使用当前配

  • Redis高并发防止秒杀超卖实战源码解决方案

    目录 1:解决思路 2:添加 redis 常量 3:添加 redis 配置类 4:修改业务层 1:秒杀业务逻辑层 2:添加需要抢购的代金券 3:抢购代金券 5:postman 测试 6:压力测试 8:配置Lua 9:修改业务层 1:抢购代金券 10:压力测试 1:解决思路 将活动写入 redis 中,通过 redis 自减指令扣除库存. 2:添加 redis 常量 commons/constant/RedisKeyConstant.java seckill_vouchers("seckill_v

  • 基于Redis过期事件实现订单超时取消

    订单超时取消的实现,首先想到的是定时任务,但是这种实现方式在订单量较大的情况下是有问题的,而且时间也会有误差,最大时间差就是定时任务的执行间隔时间. 使用redis的过期监听事件可以比较好的解决这个问题.实现的方式是订单创建后向redus中存一记录,一般就以订单号为key.设置过期时间(订单超时时间),一旦时间超时会触发监听事件,这时候就可以通过key判断这个订单是否支付,未支付时取消订单. redis过期监听的实现: 1.修改redis.windows.conf配置文件中notify-keys

  • Redis解决库存超卖问题实例讲解

    商品和订单服务间使用MQ 商品服务的库存变化时,通过 MQ 通知订单服务库存变化. 原始的同步流程 查询商品信息 (调用商品服务) 计算总价(生成订单详情) 商品服务扣库存(调用商品服务) 订单入库( 生成订单) // 原始的MySQL同步流程 // 判断此代金券是否加入抢购 SeckillVouchers seckillVouchers = seckillVouchersMapper.selectVoucher(voucherId); AssertUtil.isTrue(seckillVouc

  • Redis连接超时异常的处理方法

    0.问题描述 使用Jedis连接redis进行数据查询操作,正常的代码运行没有问题,但是时不时会报出如下错误: Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out  at redis.clients.util.RedisInputStream.ensureFill(RedisI

  • Redis中秒杀场景下超时与超卖问题的解决方案

    目录 超时 1.redis连接超时原因 2.解决方法 超卖 1.秒杀超卖现象 2.解决方案 (1)利用乐观锁淘汰用户,解决超卖问题 (2).使用reids的 watch + multi + setnx 指令实现 在开发过程中高并发问题是很棘手的一个问题(对于博主这样的小菜鸡来说),当我们学习redis之前,知道redis是单线程运行的所以任务不会出现线程不安全问题.当我们在linux中使用ab来模拟高并发秒杀时可能会遇到两种问题,“超时和超卖”. 超时 1.redis连接超时原因 (1)虚拟机中

  • PHP+Redis链表解决高并发下商品超卖问题(实现原理及步骤)

    上一篇文章聊了一下使用Redis事务来解决高并发商品超卖问题,今天我们来聊一下使用Redis链表来解决高并发商品超卖问题. 实现原理 使用redis链表来做,因为pop操作是原子的,即使有很多用户同时到达,也是依次执行,推荐使用. 实现步骤 第一步,先将商品库存入队列 /** * 添加商品数量到商品队列 * @param int $couponId 优惠券ID */ function addCoupons($couponId) { //1.初始化Redis连接 $redis = new Redi

  • PHP+Redis事务解决高并发下商品超卖问题(推荐)

    对于一些有一定用户量的电商网站,如果只是单纯的使用关系型数据库(如MySQL.Oracle)来做抢购,对数据库的压力是非常大的,而且如果不使用好数据库的锁机制,还会导致商品.优惠券超卖的问题.我所在的公司也遇到了同样的问题,问题发生在优惠券被超量抢购上,在问题发生后我们开始想办法解决问题,由于自己使用redis比较多,我准备使用redis来解决这个问题.利用redis的高性能和事务特性来解决线上优惠券被超库存抢购的问题,下面我给出我临时解决这个问题的第一版的伪代码,去掉了一些细节: /** *

  • 浅谈C++高并发场景下读多写少的优化方案

    目录 概述 分析 双缓冲 工程实现上需要攻克的难点 核心代码实现 简单说说golang中双缓冲的实现 相关文献 概述 一谈到高并发的优化方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也能很大的影响整体性能,本文从单模块下读多写少的场景出发,探讨其解决方案,以其更好的实现高并发.不同的业务场景,读和写的频率各有侧重,有两种常见的业务场景: 读多写少:典型场景如广告检索端.白名单更新维护.loadbalance

  • Redis中的String类型及使用Redis解决订单秒杀超卖问题

    本系列将和大家分享Redis分布式缓存,本章主要简单介绍下Redis中的String类型,以及如何使用Redis解决订单秒杀超卖问题. Redis中5种数据结构之String类型:key-value的缓存,支持过期,value不超过512M. Redis是单线程的,比如SetAll & AppendToValue & GetValues & GetAndSetValue & IncrementValue & IncrementValueBy等等,这些看上去像是组合命

  • Redis分布式锁解决秒杀超卖问题

    目录 分布式锁应用场景 单体锁的分类 分布式锁核心逻辑 分布式锁实现的问题——死锁和解决 Redis解决删除别人锁的问题 分布式锁应用场景 秒杀环境下:订单服务从库存中心拿到库存数,如果库存总数大于0,则进行库存扣减,并创建订单订单服务负责创建订单库存服务负责扣减库存 模拟用户访问库存 多线程并发访问,出现超卖问题,线程不安全.没有保证原子性 单体锁的分类 单体应用锁指的是只能在 一个JVM 进程内有效的锁.我们把这种锁叫做单体应用锁 synchronized锁ReentrantLock锁一个

  • 深入解析Redis中常见的应用场景

    前言 Redis是一个key-value存储系统,现在在各种系统中的使用越来越多,大部分情况下是因为其高性能的特性,被当做缓存使用,这里介绍下Redis经常遇到的使用场景.下面话不多说了,来一起看看详细的介绍吧. Redis特性 一个产品的使用场景肯定是需要根据产品的特性,先列举一下Redis的特点: 读写性能优异 持久化 数据类型丰富 单线程 数据自动过期 发布订阅 分布式 这里我们通过几个场景,不同维度说下Redis的应用. 高性能适合当做缓存 缓存是Redis最常见的应用场景,之所有这么使

  • 详解redis中的锁以及使用场景

    分布式锁 什么是分布式锁? 分布式锁是控制分布式系统之间同步访问共享资源的一种方式. 为什么要使用分布式锁? ​ 为了保证共享资源的数据一致性. 什么场景下使用分布式锁? ​ 数据重要且要保证一致性 如何实现分布式锁? 主要介绍使用redis来实现分布式锁 redis事务 redis事务介绍: ​ 1.redis事务可以一次执行多个命令,本质是一组命令的集合. ​ 2.一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入 ​ **作用:**一个队列中,一次性.顺序性.排他性的执

随机推荐