博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【商城】redis分布式缓存更新应用(击穿问题)
阅读量:4119 次
发布时间:2019-05-25

本文共 3180 字,大约阅读时间需要 10 分钟。

缓存击穿

什么是缓存击穿?数据库里面数据存在,缓存数据因某种原因不存在,导致大量请求到数据库获取数据现象。这种现象有可能会导致数据库connections数耗尽,严重会导致数据库服务停止。

分布式锁解决方案

防止请求穿透到数据库,可以使用分布式锁方式实现,例如查询商品数据;

public Product getProductById(Long productId){        log.debug("查询商品信息id:{}", productId);        //1、从本地缓存获取        Product product = ehcache.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);        if (product != null){            return product;        }        //2、从redis缓存获取        product = redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);        if (product != null){            return product;        }        //3、从db获取,防止【缓存击穿】        String uuid = UUID.randomUUID().toString();        boolean lockFlag = false;        try {            //获取分布式锁            lockFlag = redis.lock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);            if (lockFlag) {                //再次查询缓存,确保下次进入线程从缓存中获取到                product = redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);                if (product != null) {                    return product;                }                product = productService.findByProductId(productId);                if (product != null) {                    redis.setex(Constants.CACHE_PRODUCT_PREFIX + productId, EXPIRE_TIME, product);                }            }        }catch (Exception e){            log.error("分布式加锁异常", e);            return null;  //具体返回编码时候确认        }finally {            if (lockFlag){                redis.unlock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);            }        }        return product;    }

分布式锁方案优化

分布式会存在一个问题,未能获取到分布式锁的请求,会返回null空数据,可以对返回null数据进行封装,也可能采用while休眠方式等待从缓存redis中获取数据,下面以休眠方式等待为例,只对try部分代码进行重构。

try {            //获取分布式锁            lockFlag = redis.lock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);            if (lockFlag) {                //再次查询缓存,确保下次进入线程从缓存中获取到                product = redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);                if (product != null) {                    return product;                }                product = productService.findByProductId(productId);                if (product != null) {                    redis.setex(Constants.CACHE_PRODUCT_PREFIX + productId, EXPIRE_TIME, product);                }            }else{			 long endTime = 0L;             long waitTime = 0L;             while (true) {                // 一般情况下,面向用户的读请求控制在200ms                if (waitTime > 200) {                    break;                }                // 尝试再去redis中读取商品                product =  redis.get(Constants.CACHE_PRODUCT_PREFIX + productId, Product.class);                if (product  != null) {                    return product ;                } else {                    // 如果没有读取到结果,那么等待一段时间                    Thread.sleep(20);                    endTime = System.currentTimeMillis();                    waitTime = endTime - startTime;                }            }        }catch (Exception e){            log.error("分布式加锁异常", e);            return null;  //具体返回编码时候确认        }finally {            if (lockFlag){                redis.unlock(Constants.LOCK_PRODUCT_PREFIX + productId, uuid);            }        }

转载地址:http://nccpi.baihongyu.com/

你可能感兴趣的文章
linux curl命令详解
查看>>
php curl详解
查看>>
php socket编程
查看>>
linux /etc/resolv.conf /etc/hosts配置文件详解
查看>>
php配置文件详解
查看>>
nginx 代理 proxy_pass /etc/hosts
查看>>
nginx最大并发连接数的思考:worker_processes、worker_connections、worker_rlimit_nofile
查看>>
nginx配置详解
查看>>
linux 进程占用内存详解
查看>>
显示器系列1--常见参数详解
查看>>
linux cpu显示信息
查看>>
显示器系列1-我常用设备的分辨率等
查看>>
vim常见操作
查看>>
linux性能监控工具汇总
查看>>
c++ new operator和operator new,delete operator和operator delete
查看>>
linux 信号机制
查看>>
linux 软件管理方式
查看>>
TCP有效带宽
查看>>
linux free命令输出详解
查看>>
[转]C++ 虚函数表解析
查看>>