redis缓存存在的隐患及其解决方案
redis缓存
1.缓存穿透
1>.什么是缓存穿透?
业务系统需要查训的数据根本不存在,当业务系统查询时,
首先会在缓存中查训,由于缓存中不存在,然后在往数据
库中查,由于该数据在数据库中也不存在,数据库返回为空。综上所述:业务系统访问数据库中不存在的数据陈伟缓存穿透。
2>.缓存穿透的危害:
海量请求同一条数据库中不存在的数据,这些请求不经过缓存,
直接访问数据库,数据库压力剧增,业务系统中属IO最为脆弱,
这种危害可能会导致系统奔溃。
3>.为什么会发生缓存穿透?
(1).恶意攻击,故意制造大量不存在的数据,破坏整个系统。
(2).代码逻辑错误。
4>.解决方案:
(1).缓存空的数据:
redis以键值对存储数据,当第一请求数据时,数据不存在,将数据库返回的
的结果为空储存在指定的健中,后续发送请求时直接相应客户端数据不存在,
无需再次查询数据库。
(2).缓存空数据存在两个问题:
<!>.空值做了缓存,以为这缓存中要存更多的健,需要占用更多的内存空间,
如果是攻击,问题会更加严重,应该给这个健设置一个过期时间,让他自动删除。
<2>.缓存层和存储层的数据会有一段时间窗口不一致,会对业务有一定的影响
比如设置5分钟过期,如果缓存层添加这个数据,有一段时间就会出现与数据库不一致,
此时就利用消息系统或者其他方式清除缓存层的空对象
(3).布隆过滤器:
在缓存层再添加一层障碍,布隆过滤器中存储目前数据库所存在的所有key
当业务系统请求查训时,首先在布隆过滤器中查找key是否存在,若不存在,则说明
数据库中没有该条数据,因此缓存就不要查了,直接返回空对象给客户端,
若存在则进入缓存中查训,如果没有再查数据库。这个方式是用于数据命中率不高,数据相对固定稳定时性低(通常数据集较大)
的应用场景,代码维护复杂,但缓存占用空间较少。
(4).两种方案比教:
对于恶意攻击,查训的key往往不同,而且数据较多,此时,第一种方案比较合适,因为
它存储所有空数据的Key,对恶意攻击的key往往不相同,而且每个key往往只执行一次,
而不在使用第二次,但它保护不了数据库。
对空数据的的key各不相同,key重复请求依据场合而言,应该选用第二种方案,对于空数据的
key数量有限,key重复请求依据场合而言,应该选用第一种。2.缓存雪崩:1>.什么是缓存雪崩?
如果缓存因某种原因发生宕机,或者存在缓存中的数据大面积的是失效,原本
缓存抵挡的海量查训全部用涌向缓存库,因而导致整个系统崩溃。
2>.如何避免缓存雪崩:
(!).将缓存中的数据失效时间错开,过期时间做一个均匀分布的处理。
(2).排斥锁:第一个线程来读取数据,缓存中没有,先访问数据库,后续线程
再过来访问就必须等待第一个线程访问数据库成功后,再从缓存中访问。
(3)使用分布式锁,这当然是考虑到在分布式环境下,读请求会落到集群中的不同应用服务机器上。分布式锁可以选用zookeeper或基于redis的setnx这类原子性操作来实现。
加锁时需要用到经典的double-check lock。
本方案虽然能够减轻DB压力,防止雪崩。但由于用到了加锁排队,吞吐率是不高的。仅适用于并发量不大的场景。
3.缓存击穿:
1>.什么是热点数据集中失效?
缓存中的每一条数据到会设置失效时间,过了时效时间,该数据就会自动在缓存中删除,
从而保证数据的一致性。
但是,对于一些请求量极高的热点数据,一旦过了失效后海量请求最终会落到数据库上,
从而导致数据库压力极大,系统奔溃如果第一个线程请求缓存时,缓存中不存在,因而去查讯数据库,就在第一个线程查训数据,而数据库尚未返回查询结果是,
后续线程持续请求,缓存中没有数据,这些请求都会查训数据库,给数据库造成压力,
其次,这些线程持续查询完毕后,都会重复更新缓存。
4.缓存雪崩解决方案:
缓存雪崩是由于原有缓存失效(过期),新缓存未到期间。所有请求都去查询数据库,而对数据库CPU和内存造成巨大压力,严重的会
造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。
1. 碰到这种情况,一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
public object GetProductListNew(){
const int cacheTime = 30;
const string cacheKey = "product_list";
const string lockKey = cacheKey;
var cacheValue = CacheHelper.Get(cacheKey);
if (cacheValue != null){
return cacheValue;
}else{
lock (lockKey)
{
cacheValue = CacheHelper.Get(cacheKey);
if (cacheValue != null){
return cacheValue;
}else{cacheValue = GetProductListFromDB(); //这里一般是 sql查询数据。
CacheHelper.Add(cacheKey, cacheValue, cacheTime);}
}
}
return cacheValue;
}
2. 加锁排队只是为了减轻数据库的压力,并没有提高系统吞吐量。假设在高并发下,缓存重建期间key是锁着的,这是过来1000个请求
999个都在阻塞的。同样会导致用户等待超时,这是个治标不治本的方法。
还有一个解决办法解决方案是:给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓
存。
public object GetProductListNew(){
int cacheTime = 30;
string cacheKey = "product_list";
//缓存标记。
string cacheSign = cacheKey + "_sign";
//获取缓存标记
var sign = CacheHelper.Get(cacheSign);
//获取缓存值
var cacheValue = CacheHelper.Get(cacheKey);
if (sign != null)
{
return cacheValue; //未过期,直接返回。
}
else
{
//缓存标记过期后重新给缓存标记随便给值,然后缓存时间为30分钟
CacheHelper.Add(cacheSign, "1", cacheTime);
cacheValue = GetProductListFromDB(); //这里一般是 sql查询数据。
CacheHelper.Add(cacheKey, cacheValue, cacheTime*2); //日期设缓存时间的2倍,用于脏读。
return cacheValue;
}
}
redis缓存存在的隐患及其解决方案的更多相关文章
- .NET基于Redis缓存实现单点登录SSO的解决方案[转]
一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...
- .NET基于Redis缓存实现单点登录SSO的解决方案
一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...
- Redis缓存穿透和缓存雪崩以及解决方案
Redis缓存穿透和缓存雪崩以及解决方案 Redis缓存穿透和缓存雪崩以及解决方案缓存穿透解决方案布隆过滤缓存空对象比较缓存雪崩解决方案保证缓存层服务高可用性依赖隔离组件为后端限流并降级数据预热缓存并 ...
- Redis缓存雪崩、缓存穿透、热点Key解决方案和分析
缓存穿透 缓存系统,按照KEY去查询VALUE,当KEY对应的VALUE一定不存在的时候并对KEY并发请求量很大的时候,就会对后端造成很大的压力. (查询一个必然不存在的数据.比如文章表,查询一个不存 ...
- 【高并发简单解决方案】redis缓存队列+mysql 批量入库+php离线整合
原文出处: 崔小拽 需求背景:有个调用统计日志存储和统计需求,要求存储到mysql中:存储数据高峰能达到日均千万,瓶颈在于直接入库并发太高,可能会把mysql干垮. 问题分析 思考:应用网站架构的衍化 ...
- 高并发下redis缓存穿透问题解决方案
一.使用场景 我们在日常的开发中,经常会遇到查询数据列表的问题,有些数据是不经常变化的,如果想做一下优化,在提高查询的速度的同时减轻数据库的压力,那么redis缓存绝对是一个好的解决方案. 二.需求 ...
- Redis缓存雪崩,缓存穿透,热点key解决方案和分析
缓存穿透 缓存系统,按照KEY去查询VALUE,当KEY对应的VALUE一定不存在的时候并对KEY并发请求量很大的时候,就会对后端造成很大的压力. (查询一个必然不存在的数据.比如文章表,查询一个不存 ...
- Redis缓存穿透、缓存雪崩、redis并发问题 并发竞争key的解决方案 (阿里)
阿里的人问我 缓存雪崩(大量数据在同一时间过期了)了如何处理,缓存击穿了如何处理,回答的很烂,做了总结: 把redis作为缓存使用已经是司空见惯,但是使用redis后也可能会碰到一系列的问题,尤其是数 ...
- redis缓存穿透穿透解决方案-布隆过滤器
redis缓存穿透穿透解决方案-布隆过滤器 我们先来看一段代码 cache_key = "id:1" cache_value = GetValueFromRedis(cache_k ...
随机推荐
- 基础知识之nginx重写规则
nginx重写规则 nginx rewrite 正则表达式匹配 大小写匹配 ~ 为区分大小写匹配 ~* 为不区分大小写匹配 !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 文件及目录匹配 -f ...
- 新加了一块硬盘,在bios中可以看的到,在系统的磁盘管理器中看不到新加硬盘
今天新加了一块硬盘,进入bios中可以看到新加的硬盘,但是进入系统后在磁盘管理及磁盘驱动器中都看不到.并且在设备管理器下其他设备出现了ATA channel1,前面显示感叹号,如下图所示: 而且电脑变 ...
- JS中的计时器事件
JS可以实现很多java代码不易完成的功能.这里学习一些js中的计时器事件. JavaScript 一个设定的时间间隔之后来执行代码,称之为计时事件. 主要通过两个方法来实现: 1.setInterv ...
- Typecho 二次开发文档链接
快速入门模板入门 模板制作快速入门推荐目录结构 Typecho模板的推荐页面构成模板文件说明 Typecho主题制作文件结构 页面制作制作functions文件: Typecho的functions. ...
- asp.net文件上传下载
泽优大文件上传产品测试 泽优大文件上传控件up6,基于php开发环境测试. 开发环境:HBuilder 服务器:wamp64 数据库:mysql 可视化数据库编辑工具:Navicat Premium ...
- _编程语言_C++_宏定义#define 和 常量const 的区别
C++中有两种定义常量的方式:#define预处理和const关键字 #define 预处理指令 #include <iostream> using namespace std; #def ...
- Codeforces Round #540 (Div. 3)--1118D1 - Coffee and Coursework (Easy version)
https://codeforces.com/contest/1118/problem/D1 能做完的天数最大不超过n,因为假如每天一杯咖啡,每杯咖啡容量大于1 首先对容量进行从大到小的排序, sor ...
- SurfaceView+MediaPlayer播放视频
SurfaceView拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行行绘制.又由于不占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不 ...
- bootstrap2.1相关文档
本节课我们主要学习一下 Bootstrap表格和按钮功能,通过内置的 CSS定义,显示各种丰富的效果. 一.表格 Bootstrap提供了一些丰富的表格样式供开发者使用. 1.基本格式 //实现基本的 ...
- AngularJS 服务 provider factory service及区别
一.概念说明 1.服务是对公共代码的抽象,如多个控制器都出现了相似代码,把他们抽取出来,封装成一个服务,遵循DRY原则,增强可维护性,剥离了和具体表现相关的部分,聚焦于业务逻辑或交互逻辑,更加容易被测 ...