Redis专题-缓存穿透、缓存雪崩、缓存击穿
一.缓存穿透
缓存穿透概念
缓存穿透是指查询一个一定不存在的数据,在数据库没有,自然在缓存中也不会有。导致用户查询的时候,在缓存中找不到对应key的value,每次都要去数据库再查询一遍,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
缓存穿透解决方案
有很多种方法可以有效地解决缓存穿透问题。
缓存空值
如果一个查询返回的数据为空(不管是数据不存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过5分钟。通过这个设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库。
采用布隆过滤器BloomFilter
在缓存之前加一层BloomFilter,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。在查询的时候先去BloomFilter去查询key是否存在,如果不存在就直接返回,存在再去查询缓存,缓存中没有再去查询数据库。对BloomFilter有兴趣的可以看我的另一篇文章教你用BitMap排序、查找和存储大量数据。
二.缓存雪崩
缓存雪崩概念
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。
缓存雪崩解决方案
设置不同的过期时间,让缓存失效的时间点尽量均匀
在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
考虑用队列或者锁让程序执行在压力范围之内,当然这种方案可能会影响并发量;
热点数据可以考虑不失效。
三.缓存击穿
缓存击穿概念
在平常高并发的系统中,大量的请求同时查询一个key,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去,造成数据库请求量过大,压力剧增,这种现象我们称为缓存击穿。
缓存击穿解决方案
使用互斥锁(mutex key)
业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存,否则,就重试整个get缓存的方法。
SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。
redis2.6.1之前版本未实现setnx的过期时间,这里给出两种版本代码参考:
//2.6.1之前
String get(String key) { String value = redis.get(key); if (value == null) { if (redis.setnx(key_mutex, "1")) { // 3 min timeout to avoid mutex holder crash redis.expire(key_mutex, 3 * 60) value = db.get(key); redis.set(key, value); redis.delete(key_mutex); } else { //其他线程休息50毫秒后重试 Thread.sleep(50); get(key); } }
}
//2.6.1之后
String get(key) {String value = redis.get(key);if (value == null) { //代表缓存值过期//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load dbif (redis.setnx(key_mutex, 1, 3 * 60) == 1) { //代表设置成功value = db.get(key);redis.set(key, value, expire_secs);redis.del(key_mutex);} else { //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可sleep(50);get(key); //重试}} else {return value; }}
永远不过期
这里的“永远不过期”包含两层意思:
- 从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期;
- 从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期。
String get(final String key) { V v = redis.get(key); String value = v.getValue(); long timeout = v.getTimeout(); if (v.timeout <= System.currentTimeMillis()) { // 异步更新后台异常执行 threadPool.execute(new Runnable() { public void run() { String keyMutex = "mutex:" + key; if (redis.setnx(keyMutex, "1")) { // 3 min timeout to avoid mutex holder crash redis.expire(keyMutex, 3 * 60); String dbValue = db.get(key); redis.set(key, dbValue); redis.delete(keyMutex); } } }); } return value;
}
从实战看,这种方法对于性能非常友好,唯一不足的就是构建缓存时候,其余线程(非构建缓存的线程)可能访问的是老数据,但是对于一般的互联网功能来说这个还是可以忍受。
猜你感兴趣:
Redis专题-集群模式
Redis专题-持久化方式
Redis专题-底层数据结构与使用场景
Redis专题-缓存穿透、缓存雪崩、缓存击穿
更多文章请点击:更多…
Redis专题-缓存穿透、缓存雪崩、缓存击穿相关推荐
- Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)
一.概述 ① 缓存穿透:大量请求根本不存在的key(下文详解) ② 缓存雪崩:redis中大量key集体过期(下文详解) ③ 缓存击穿:redis中一个热点key过期(大量用户访问该热点key,但是热 ...
- 什么是缓存穿透、雪崩、击穿以及解决方案
目录 1.缓存穿透 2.缓存雪崩 3.缓存击穿 4.区别总结 5.加锁实现 1.缓存穿透 描述: 在查询一个数据时,在缓存中不存在,将去数据库进行查询并且数据库中也不存在数据,使得缓存中一直不会存在数 ...
- 一篇吃透Redis缓存穿透、雪崩、击穿问题
前言:在学Redis之前我们查询数据的时候都是直接查询数据库的,但是这样会有一个潜在的问题:"如果用户量很大,所有请求都去访问数据库,那么会使数据库压力过大,导致性能下降甚至宕机" ...
- mysql数据库击穿_面试中经常出现的缓存穿透、雪崩和击穿到底是什么?
对于缓存穿透.缓存雪崩和缓存击穿常常出现在面试中,今天来看看它到底是何方神圣 redis缓存穿透 理解重在穿透吧,也就是访问透过redis直接经过mysql,通常是一个不存在的key,在数据 ...
- 缓存穿透、雪崩、击穿的区分
缓存穿透: 是指用户查询一个不存在的数据,由于缓存无法命中,将去查询数据库,但是数据库也无此记录,并且出于容错考虑,我们没有将这次查询的null写入缓存,这将导致这个不存在的数据每次请求都要到存储层去 ...
- Redis全部知识总结(概念、安装、用法、数据类型、事务、持久化、Jeids、订阅系统、缓存穿透及雪崩等)
Redis NoSql简述 Nosql概念 Nosql的四大分类 Redis概述 Redis的安装 安装文件 Window下安装 Linux下安装 redis-benchmark 压力测试工具 五大数 ...
- Redis11_缓存穿透和雪崩
Redis11_缓存穿透和雪崩 缓存穿透 用户查询某个数据时,会先在redis缓存中查询,如果缓存没有命中,会去持久层数据库MySQL中查询,如果此时依然没有命中,将返回null,不会写入缓存. 当同 ...
- 二十七、Redis缓存穿透和雪崩(完)
Redis缓存穿透和雪崩 一.服务的高可用问题 在这里我们不会详细的区分析解决方案的底层! Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面.但同时,它也带来了一些问题.其中 ...
- 21_Redis_浅析Redis缓存穿透和雪崩
为什么了解缓存穿透和雪崩:保证服务的高可用问题 Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面.但同时,它也带来了一些问题.其中,最要害的问题,就是数据的一致性问题,从严格 ...
- Redis 缓存穿透、雪崩、缓存数据库不一致、持久化方式、分布式锁、过期策略
1. Redis 缓存穿透 1.1 Redis 缓存穿透概念 访问了不存在的 key,缓存未命中,请求会穿透到 DB,量大时可能会对 DB 造成压力导致服务异常. 由于不恰当的业务功能实现,或者外部恶 ...
最新文章
- windows php-cgi命令选项,windows平台上php-cgi调用系统命令(net)时执行异常,但在命令行下能正常执行,问题会出在哪呢?...
- CTFshow php特性 web134
- 15个学习习惯,受益一生(强烈推荐)
- 涂鸦板练习(20200214)
- 限制tomcat带宽_必看的Tomcat性能优化
- [html] html5哪些标签可以优化SEO?
- 10年腾讯技术专家有话对你说
- java velocity 语法_Velocity 语法
- php表决器代码,adder3 此源代码是基于Verilog语言的七人投票表决器 、2 个 联合开发网 - pudn.com...
- macbook只有windows下安装os系统、trackpad++下载
- Redis数据存储类型
- Windows10查看本机连接过的WiFi密码
- 【微信小程序】深入学习小程序基本目录文件与代码结构
- C#串口开发案例:迈瑞血球分析仪
- 基于ZYNQ的开源CANopen协议栈CANFestival移植
- 成年人英语速成指南(附资源及工具)
- 1.background、color、渐变
- 修改Centos7.6服务器时间
- Vue开发入门(二) | 说说Vue全家桶有哪些~
- [转]谈NAND Flash的底层结构和解析