菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
254
0

【分布式】缓存穿透、缓存雪崩,缓存击穿解决方案,使用锁控制缓存的加载

原创
05/13 14:22
阅读数 41333

 

原文:https://www.cnblogs.com/dream-to-pku/p/9153999.html

 

 

static Lock reenLock = new ReentrantLock();
 
    public List<String> getData04() throws InterruptedException {
        List<String> result = new ArrayList<String>();
        // 从缓存读取数据
        result = getDataFromCache();
        if (result.isEmpty()) {
            if (reenLock.tryLock()) {
                try {
                    System.out.println("我拿到锁了,从DB获取数据库后写入缓存");
                    // 从数据库查询数据
                    result = getDataFromDB();
                    // 将查询到的数据写入缓存
                    setDataToCache(result);
                } finally {
                    reenLock.unlock();// 释放锁
                }
 
            } else {
                result = getDataFromCache();// 先查一下缓存
                if (result.isEmpty()) {
                    System.out.println("我没拿到锁,缓存也没数据,先小憩一下");
                    Thread.sleep(100);// 小憩一会儿
                    return getData04();// 重试
                }
            }
        }
        return result;
    }

 

 

原文:https://my.oschina.net/u/3434392/blog/3012132

缓存雪崩

指的是大量缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。

解决办法

  1. 这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布,设置不同的过期时间。
  2. 用加分布式锁或者分布式队列的方式保证缓存的单线程(进程)写 (eg. redis的 SETNX),从而避免失效时大量的并发请求落到底层存储系统上。在加锁方法内先从缓存中再获取一次(防止另外的线程优先获取锁已经写入了缓存),没有再查DB写入缓存。 (当然也可以: 在没有获取锁(tryLock)的线程中一直轮询缓存,至超限时)

缓存击穿

指的是热点key在某个特殊的场景时间内恰好失效了,恰好有大量并发请求过来了,造成DB压力。

解决办法

与缓存雪崩的解决方法类似: 用加锁或者队列的方式保证缓存的单线程(进程)写,在加锁方法内先从缓存中再获取一次,没有再查DB写入缓存。 

还有一种比较好用的(针对缓存雪崩与缓存击穿):

物理上的缓存是不设置超时时间的(或者超时时间比较长), 但是在缓存的对象上增加一个属性来标识超时时间(此时间相对小)。 当获取到数据后,校验数据内部的标记时间,判定是否快超时了,如果是,异步发起一个线程(控制好并发)去主动更新该缓存。

这种方式会导致一定时间内,有些请求获取缓存会拿到过期的值,看业务是否能接受而定。

 

发表评论

0/200
254 点赞
0 评论
收藏
为你推荐 换一批