IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Redis(二十三)-秒杀案例之超卖和超时问题解决 -> 正文阅读

[大数据]Redis(二十三)-秒杀案例之超卖和超时问题解决

您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦
💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精通
?? 2. Python爬虫专栏,系统性的学习爬虫的知识点。9.9元买不了吃亏,买不了上当 。python爬虫入门进阶
?? 3. Ceph实战,从原理到实战应有尽有。 Ceph实战
?? 4. Java高并发编程入门,打卡学习Java高并发。 Java高并发编程入门
😁 5. 社区逛一逛,周周有福利,周周有惊喜。码农飞哥社区,飞跃计划
全网同名【码农飞哥】欢迎关注,个人VX: wei158556

简介

上一篇文章我们介绍秒杀案例的基本实现 Redis(二十二)-秒杀案例的基本实现以及用ab工具模拟并发。但是在文章的最后留了两个问题没有解决,一个是高并发情况下的超卖问题,以及jedis客户端请求超时问题。这篇文章就是来解决这两篇问题。

超时问题解决

超时问题的现象

java.net.SocketTimeoutException: connect timed out
	at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) ~[na:1.8.0_60]
	at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) ~[na:1.8.0_60]
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_60]
	at 

超时问题的原因

因为在上面的案例中是每次都会创建一个新的连接实例,而创建连接实例又是一个比较耗时的动作。故会出现超时问题。
那么,解决超时问题可以利用jedis的线程池,节省每次连接redis服务带来的消耗,把连接好的实例反复利用。
通过参数管理连接的行为,代码如下:

public class JedisPoolUtil {
    private static JedisPool jedisPool;
    private JedisPoolUtil() {

    }
    //通过单例模式来定义jedisPool连接池
    public static JedisPool getJedisPool() {
        synchronized (JedisPoolUtil.class) {
            if (jedisPool == null) {
                JedisPoolConfig poolConfig = new JedisPoolConfig();
                poolConfig.setMaxTotal(200);
                poolConfig.setMaxIdle(32);
                poolConfig.setMaxWaitMillis(100 * 1000);
                poolConfig.setBlockWhenExhausted(true);
                poolConfig.setTestOnBorrow(true);
                //指定连接池的poolConfig,redis的IP地址,端口号,已经超时时间。
                jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379,60000);
            }
        }
        return jedisPool;
    }
	//释放jedis连接
    public static void release(JedisPool jedisPool, Jedis jedis) {
        if (jedis != null) {
            jedisPool.returnResource(jedis);
        }
    }
}

其中连接池参数:

  1. MaxTotal :控制一个pool可以分配多少个jedis实例,通过pool.getResource()来获取,如果赋值为-1,则表示不限制,如果pool已经分配了MaxTotal个jedis实例,则此时pool的状态为exhausted。
  2. MaxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
  3. MaxWaitMillis:表示当borrow一个jedis实例时,最大的等待毫秒数,如果超过等待时间,则直接抛JedisConnectionException;

再将原来的 Jedis jedis = new Jedis("127.0.0.1", 6379); 替换成 Jedis jedis = JedisPoolUtil.getJedisPool().getResource(); 表示从连接池中获取Jedis连接实例。
再次测试一下:
在这里插入图片描述

超卖问题解决

之所以出现超卖的情况还是因为在并发的情况下出现了线程安全的问题,即两个线程同时需减同一个库存。主要是如下代码有问题:

       // 4.获取库存,如果库存null,秒杀还没有开始
		String skValue = jedis.get(skKey);
        if (skValue == null) {
            System.out.println("秒杀还没开始,请等待");
            return false;
        }
        // 6. 判断如果商品数量,库存数量小于1,秒杀结束
        if (Integer.parseInt(skValue) <= 0) {
            System.out.println("该商品的库存不足,秒杀失败");
            return false;
        }
        // 7. 秒杀过程
        //    7.1. 库存-1
        jedis.decr(skKey);
        //    7.2. 用户加入到set集合中
        jedis.sadd(userKey, uid);

比如说现在还剩下最后一个库存,现在两个线程同时获取到库存值为1,两者又同时去修改库存值,最终的库存值就会被减成负数。
要解决这个问题话,还是需要用到前面提到的乐观锁,用乐观锁去监视库存值,哪怕出现上述的情况,由于第一个线程修改库存值之后,版本号也被修改了。故第二个线程不能修改成功。所以就不会出现超卖的情况。核心代码如下:

        String skKey = "sk:" + prodid + ":qt";
	  //监视库存
        jedis.watch(skKey);
        // 4.获取库存,如果库存null,秒杀还没有开始
        String skValue = jedis.get(skKey);
        if (skValue == null) {
            System.out.println("秒杀还没开始,请等待");
            return false;
        }
  //增加事务
        Transaction multi = jedis.multi();
        //组队操作
        multi.decr(skKey);
        multi.sadd(userKey, uid);
        //执行
        List<Object> results = multi.exec();
        if (results == null || results.size() == 0) {
            System.out.println("秒杀失败了。。。");
            jedis.close();
            return false;
        }

这里通过watch方法监视库存的键 sk:1010:qt。然后将 减库存decr方法以及增加用户sadd方法放在事务队列,最后在通过exec方法依次执行事务队列中的命令。最终的运行结果如下:
在这里插入图片描述
在这里插入图片描述
这里给商品qt设置了30个库存,最终执行完成之后还剩下8个库存。虽然超卖的问题解决了但是还有一个新的问题:库存遗留问题。下一篇文章会接着来说下如何处理库存遗留问题。

总结

本文详细介绍了如何解决秒杀案例中的超卖以及超时问题。希望对读者朋友们有所帮助。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-05-07 11:15:14  更:2022-05-07 11:15:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:57:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码