缓存穿透、缓存雪崩、缓存击穿场景模拟、解决方案

cache-best-practice

 

一、缓存穿透、缓存雪崩、缓存击穿场景模拟

查询方法代码

    /**
     * 缓存穿透、缓存击穿、缓存雪崩问题
     *
     * @param id
     * @return
     */
    public DataObject getData1(Long id) {
        //从缓存读取数据
        DataObject result = getDataFromCache(id);
        if (result == null) {
            // 从数据库查询数据
            result = getDataFromDB(id);
            if (result != null) {
                // 将查询到的数据写入缓存
                setDataToCache(id, result);
            }
        }
        return result;
    }

 

1、缓存穿透

缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常处于容错的考虑,如果从缓存层查询不到数据则不写入缓存层

缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端存储层的意义

缓存穿透模拟:

数据库中存在ID 1至100 的数据,我们并发查询数据库中不存在的记录ID 101至110

采用JMeter模拟并发请求,打开“场景模拟-缓存穿透.jmx”执行请求

执行并发请求后,查询日志可以看出,所有请求每次都走向了数据库,以下为日志片段

......
从【缓存】中获取数据, id: 110, DataObject: null
从【数据库】中获取数据, id: 110, DataObject: null
从【缓存】中获取数据, id: 106, DataObject: null
从【缓存】中获取数据, id: 103, DataObject: null
从【数据库】中获取数据, id: 103, DataObject: null
从【缓存】中获取数据, id: 102, DataObject: null
从【数据库】中获取数据, id: 102, DataObject: null
从【缓存】中获取数据, id: 108, DataObject: null
从【数据库】中获取数据, id: 108, DataObject: null
从【缓存】中获取数据, id: 106, DataObject: null
从【数据库】中获取数据, id: 106, DataObject: null
从【缓存】中获取数据, id: 103, DataObject: null
从【数据库】中获取数据, id: 103, DataObject: null
从【缓存】中获取数据, id: 107, DataObject: null
从【数据库】中获取数据, id: 107, DataObject: null
从【缓存】中获取数据, id: 102, DataObject: null
从【数据库】中获取数据, id: 102, DataObject: null
从【缓存】中获取数据, id: 110, DataObject: null
从【数据库】中获取数据, id: 110, DataObject: null
从【数据库】中获取数据, id: 106, DataObject: null
从【缓存】中获取数据, id: 107, DataObject: null
从【缓存】中获取数据, id: 109, DataObject: null
从【数据库】中获取数据, id: 109, DataObject: null
从【数据库】中获取数据, id: 107, DataObject: null
从【缓存】中获取数据, id: 110, DataObject: null
从【数据库】中获取数据, id: 110, DataObject: null
......

 

2、缓存雪崩

在普通的缓存系统中一般例如redis、memcache等中,我们会给缓存设置一个失效时间,但是如果所有的缓存的失效时间相同,那么在同一时间失效时,所有系统的请求都会发送到数据库层,db可能无法承受如此大的压力导致系统崩溃。

 

缓存雪崩模拟:

  • 1、同时设置ID 1至100 的缓存
  • 2、查询1~100的数据,命中缓存
  • 3、手动删除ID 1至10 的缓存,模拟缓存失效
  • 4、100并发请求ID 1至10 的数据30次

采用JMeter模拟并发请求,打开“场景模拟-缓存雪崩.jmx”执行请求

执行第4步后,查询日志可以看出大量请求到达数据库,并且同一个ID执行了多次数据库查询,日志片段如下

......
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: null
从【缓存】中获取数据, id: 7, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: null
从【缓存】中获取数据, id: 9, DataObject: null
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: null
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 7, DataObject: null
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 7, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 9, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: null
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: null
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: null
从【数据库】中获取数据, id: 1, DataObject: DataObject(id=1, desc=name:1)
设置数据到【缓存】, DataObject: DataObject(id=1, desc=name:1)
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: null
从【数据库】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 5, DataObject: null
从【数据库】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
设置数据到【缓存】, DataObject: DataObject(id=5, desc=name:5)
设置数据到【缓存】, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 7, DataObject: null
从【数据库】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
设置数据到【缓存】, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 10, DataObject: null
从【数据库】中获取数据, id: 10, DataObject: DataObject(id=10, desc=name:10)
设置数据到【缓存】, DataObject: DataObject(id=10, desc=name:10)
......

 

3、缓存击穿

对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。
缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

 

缓存击穿模拟:

  • 1、查询ID为50的请求,这时id为50的数据会加载到缓存
  • 2、再次查询ID为50的请求,命中缓存
  • 3、300并发请求ID为50的数据,这个时候请求全部命中缓存
  • 4、将ID为50的缓存手动删除,模拟缓存失效
  • 5、300并发请求ID为50的数据,这个时候大量请求走向数据库,ID为50的缓存被击穿
curl http://127.0.0.1:8080/data/getData1?id=50
curl http://127.0.0.1:8080/data/getData1?id=50

采用JMeter模拟并发请求,打开“场景模拟-缓存击穿.jmx”执行请求

curl http://127.0.0.1:8080/data/deleteCache?id=50

再次执行JMeter并发请求

执行第3步后,查询日志可以看出请求全部命中缓存,以下为日志片段

......
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从缓存中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
......

执行第5步后,查询日志可以看出ID为50的请求多次查询了数据库并设置缓存,之后才命中缓存,以下为日志片段

......
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
......

 

二、最佳实践方案测试

 

优化后的查询方法代码

public DataObject getData(Long id) {
        //从缓存读取数据
        DataObject result = getDataFromCache(id);
        if (result == null) {
            //缓存不存在,从数据库查询数据的过程加上锁,避免缓存击穿导致数据库压力过大
            RLock lock = redissonClient.getLock(DATA_LOCK_NAME + id);
            lock.lock(15, TimeUnit.SECONDS);
            if (lock.isLocked()) {
                try {
                    //双重判断,第二个以及之后的请求不必去找数据库,直接命中缓存
                    //再次查询缓存
                    result = getDataFromCache(id);
                    if (result == null) {
                        // 从数据库查询数据
                        result = getDataFromDB(id);
                        // 将查询到的数据写入缓存
                        setDataToCache(id, result);
                    }
                } finally {
                    //锁只能被拥有它的线程解锁
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            }
        } else {
            if (result.getId() == ID_NOT_EXISTS) {
                return null;
            }
        }
        return result;
    }

1、缓存穿透

测试计划:线程数100,重复执行1次

并发查询数据库中不存在的ID 101至110 的数据,可以看出每个ID都只执行了一次数据库查询并设置缓存,之后请求都命中了缓存,有效防止了缓存穿透问题,以下为日志片段

......
从【缓存】中获取数据, id: 110, DataObject: null
从【缓存】中获取数据, id: 107, DataObject: null
从【缓存】中获取数据, id: 107, DataObject: null
从【缓存】中获取数据, id: 106, DataObject: null
从【缓存】中获取数据, id: 110, DataObject: null
从【缓存】中获取数据, id: 104, DataObject: null
从【缓存】中获取数据, id: 109, DataObject: null
从【缓存】中获取数据, id: 108, DataObject: null
从【缓存】中获取数据, id: 107, DataObject: null
从【缓存】中获取数据, id: 102, DataObject: null
从【缓存】中获取数据, id: 110, DataObject: null
从【缓存】中获取数据, id: 106, DataObject: null
从【缓存】中获取数据, id: 101, DataObject: null
从【缓存】中获取数据, id: 103, DataObject: null
从【缓存】中获取数据, id: 105, DataObject: null
从【数据库】中获取数据, id: 109, DataObject: null
设置数据到【缓存】, DataObject: null
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【数据库】中获取数据, id: 105, DataObject: null
设置数据到【缓存】, DataObject: null
从【数据库】中获取数据, id: 110, DataObject: null
设置数据到【缓存】, DataObject: null
从【数据库】中获取数据, id: 106, DataObject: null
设置数据到【缓存】, DataObject: null
从【数据库】中获取数据, id: 107, DataObject: null
设置数据到【缓存】, DataObject: null
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 105, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 110, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 106, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 107, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 105, DataObject: DataObject(id=-1, desc=null)
从【数据库】中获取数据, id: 102, DataObject: null
设置数据到【缓存】, DataObject: null
从【数据库】中获取数据, id: 103, DataObject: null
设置数据到【缓存】, DataObject: null
从【缓存】中获取数据, id: 110, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 106, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 107, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 105, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 102, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 103, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 110, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 106, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 107, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 105, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 102, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 110, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 103, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 106, DataObject: DataObject(id=-1, desc=null)
从【数据库】中获取数据, id: 104, DataObject: null
设置数据到【缓存】, DataObject: null
从【缓存】中获取数据, id: 107, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 105, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 102, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 103, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 110, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 106, DataObject: DataObject(id=-1, desc=null)
从【数据库】中获取数据, id: 108, DataObject: null
设置数据到【缓存】, DataObject: null
从【缓存】中获取数据, id: 104, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 107, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 109, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 105, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 102, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 103, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 110, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 106, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 104, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 108, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 107, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 105, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 103, DataObject: DataObject(id=-1, desc=null)
从【缓存】中获取数据, id: 102, DataObject: DataObject(id=-1, desc=null)
从【数据库】中获取数据, id: 101, DataObject: null
设置数据到【缓存】, DataObject: null
......

 

加入布隆过滤器

public DataObject getData(Long id) {
        //布隆过滤器中不存在,则直接返回空
        if (!clusterClient.exists(DATA_BF_NAME, ObjectUtils.nullSafeToString(id))) {
            System.out.println("布隆过滤器中不存在, id: " + id);
            return null;
        }
        //从缓存读取数据
        DataObject result = getDataFromCache(id);
        if (result == null) {
            //缓存不存在,从数据库查询数据的过程加上锁,避免缓存击穿导致数据库压力过大
            RLock lock = redissonClient.getLock(DATA_LOCK_NAME + id);
            lock.lock(15, TimeUnit.SECONDS);
            if (lock.isLocked()) {
                try {
                    //双重判断,第二个以及之后的请求不必去找数据库,直接命中缓存
                    //再次查询缓存
                    result = getDataFromCache(id);
                    if (result == null) {
                        // 从数据库查询数据
                        result = getDataFromDB(id);
                        // 将查询到的数据写入缓存
                        setDataToCache(id, result);
                    }
                } finally {
                    //锁只能被拥有它的线程解锁
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                    }
                }
            }
        } else {
            if (result.getId() == ID_NOT_EXISTS) {
                return null;
            }
        }
        return result;
    }

再次执行jmeter测试,可以看到ID在布隆过滤器中不存在,直接返回了(由于布隆过滤器会存在概率误判,所以有的ID可能会执行后面的缓存和数据库查询)。日志片段如下

......
布隆过滤器中不存在, id: 107
布隆过滤器中不存在, id: 101
布隆过滤器中不存在, id: 104
布隆过滤器中不存在, id: 106
布隆过滤器中不存在, id: 103
布隆过滤器中不存在, id: 101
布隆过滤器中不存在, id: 102
布隆过滤器中不存在, id: 103
布隆过滤器中不存在, id: 101
布隆过滤器中不存在, id: 105
布隆过滤器中不存在, id: 101
布隆过滤器中不存在, id: 103
布隆过滤器中不存在, id: 106
布隆过滤器中不存在, id: 107
布隆过滤器中不存在, id: 110
布隆过滤器中不存在, id: 108
布隆过滤器中不存在, id: 109
布隆过滤器中不存在, id: 110
布隆过滤器中不存在, id: 102
布隆过滤器中不存在, id: 101
布隆过滤器中不存在, id: 104
布隆过滤器中不存在, id: 102
布隆过滤器中不存在, id: 109
布隆过滤器中不存在, id: 110
布隆过滤器中不存在, id: 101
布隆过滤器中不存在, id: 107
布隆过滤器中不存在, id: 110
布隆过滤器中不存在, id: 109
......

2、缓存雪崩

测试计划:线程数为100,重复执行30次

并发请求失效缓存ID为 1至10 的记录,可以看到每个ID都只查询了一次数据库并设置缓存,之后的请求都命中了缓存

从【缓存】中获取数据, id: 9, DataObject: null
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 7, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 9, DataObject: null
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 9, DataObject: null
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 1, DataObject: null
从【数据库】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
设置数据到【缓存】, DataObject: DataObject(id=4, desc=name:4)
从【数据库】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
设置数据到【缓存】, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【数据库】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
设置数据到【缓存】, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 5, DataObject: null
从【缓存】中获取数据, id: 7, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 9, DataObject: null
从【数据库】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
设置数据到【缓存】, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 2, DataObject: null
从【数据库】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
设置数据到【缓存】, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【数据库】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
设置数据到【缓存】, DataObject: DataObject(id=9, desc=name:9)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 6, DataObject: null
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 10, DataObject: null
从【数据库】中获取数据, id: 6, DataObject: DataObject(id=6, desc=name:6)
设置数据到【缓存】, DataObject: DataObject(id=6, desc=name:6)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
从【缓存】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 6, DataObject: DataObject(id=6, desc=name:6)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 1, DataObject: null
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【数据库】中获取数据, id: 1, DataObject: DataObject(id=1, desc=name:1)
设置数据到【缓存】, DataObject: DataObject(id=1, desc=name:1)
从【缓存】中获取数据, id: 6, DataObject: DataObject(id=6, desc=name:6)
从【缓存】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 1, DataObject: null
从【数据库】中获取数据, id: 2, DataObject: DataObject(id=2, desc=name:2)
设置数据到【缓存】, DataObject: DataObject(id=2, desc=name:2)
从【缓存】中获取数据, id: 6, DataObject: DataObject(id=6, desc=name:6)
从【缓存】中获取数据, id: 2, DataObject: null
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 6, DataObject: DataObject(id=6, desc=name:6)
从【缓存】中获取数据, id: 8, DataObject: DataObject(id=8, desc=name:8)
从【缓存】中获取数据, id: 9, DataObject: DataObject(id=9, desc=name:9)
从【数据库】中获取数据, id: 10, DataObject: DataObject(id=10, desc=name:10)
设置数据到【缓存】, DataObject: DataObject(id=10, desc=name:10)
从【缓存】中获取数据, id: 10, DataObject: null
从【缓存】中获取数据, id: 1, DataObject: DataObject(id=1, desc=name:1)
从【缓存】中获取数据, id: 4, DataObject: DataObject(id=4, desc=name:4)
从【缓存】中获取数据, id: 5, DataObject: DataObject(id=5, desc=name:5)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)
从【缓存】中获取数据, id: 2, DataObject: DataObject(id=2, desc=name:2)
从【缓存】中获取数据, id: 3, DataObject: DataObject(id=3, desc=name:3)
从【缓存】中获取数据, id: 6, DataObject: DataObject(id=6, desc=name:6)
从【缓存】中获取数据, id: 7, DataObject: DataObject(id=7, desc=name:7)

3、缓存击穿

测试计划:线程数为100,重复执行1次

先让ID为50的缓存失效

curl http://127.0.0.1:8080/data/deleteCache?id=50

并发请求失效缓存ID为50的记录,可以看到只有一个请求执行了数据库查询并设置缓存,其他请求都命中了缓存,日志片段如下:

......
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【缓存】中获取数据, id: 50, DataObject: null
从【数据库】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
设置数据到【缓存】, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
从【缓存】中获取数据, id: 50, DataObject: DataObject(id=50, desc=name:50)
......

 

完整项目代码参考: cache-best-practice
内含jmeter测试脚本

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章