redis缓存问题解决方案

缓存击穿

  名词解释:当我们缓存key设置过期时间,恰巧在这一刻这个key在某一刻被高并发的访问,把所有的请求都打到了DB中这就可能会导致DB挂了。这个跟后面说的缓存雪崩非常相似,这个和缓存雪崩的区别在于这里针对某一key缓存,但是雪崩则指的是多个key,要解决方案有很多,比如让一个线程构建缓存,另外线程等待知道构建好,或者redis维护timeout字段逻辑失效等等

String get(final String key) {  

        T t = redis.get(key);  

        String value = t.getValue();  

        long timeout = t.getTimeout();  

        // 当逻辑的超时时间到了时,异步构建缓存  

        if (timeout <= System.currentTimeMillis()) {  

            threadPool.execute(new Runnable() {  

                public void run() {  

                    String brokenKey = "broken_"+key;  

                    if (redis.setnx(brokenKey, "1")) {  //redis加锁 更新过期时间

                        redis.expire(brokenKey, 60);  //防止产生key不失效

                        String dbValue = db.get(key);  

                        redis.set(key, dbValue);  

                        redis.del(brokenKey);  

                    }  

                }  

            });  

        }  

        return value;  

    }

  缓存穿透:看了上面介绍的缓存击穿了,现在怎么又出现了一个缓存穿透呢,感觉字面上穿透和击穿应该是一个意思啊,确实个人理解翻译上是差不多,但是对于redis的专业技术语上却是不同,缓存穿透指的是一些恶意人攻击,比如说登录的时候它请求一个一定不存在的用户名时,那么我们服务端正常应该是这样处理,首先到缓存中查询,没有在到数据查询,看看好像是没问题啊,查询一下应该很快,如果是这一刻恶意攻击发起几百万次请求,所以就会一直循环这个操作,一定不存在的用户名会一直查询数据库,那么你的数据库和缓存系统会不会挂呢?

  方法1、布隆过滤器处理,把key放到布隆过滤器中,获取时查看是否存在,如果存在则获取缓存、获取数据库(把key放入缓存又2种方案,1、业务系统初始化 2、缓存中获取不到时单条插入到布隆过滤器)

  优点: 高性能

  缺点:布隆过滤器不支持删除,需要单独维护一个缓存key的集合, 另外布隆过滤器是有一定误差的。

   方法2、也可以采用一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,然后但它的过期时间会很短,最长不超过五分钟。

 缓存空对象会有两个问题:

 第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。

 第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

缓存雪崩  

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

    这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。

详细见

https://blog.csdn.net/lby0307/article/details/79680326

猜你喜欢

转载自www.cnblogs.com/tjqBlog/p/10520144.html