缓存,这么用才真正达到缓存的效果
Posted 支付技术那些事
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了缓存,这么用才真正达到缓存的效果相关的知识,希望对你有一定的参考价值。
本文内容:
1. 什么是缓存?
平常的开发项目中,多多少少都会使用到缓存,因为一些数据我们没有必要每次查询的时候都去查询到数据库。
一个形象的比喻
数据库是人的身体,
缓存是防弹衣,
子弹就是去后台拿数据的请求线程,
防弹衣是防止子弹打到人身体上。
缓存的目的就是为了某些查找数据操作,查询的更快,同时保护好下游的数据库。
2. 缓存的使用场景
分析一个系统是否需要使用缓存,具体业务数据是否适合做缓存,我们要从一些指标或者要求去分析。
使用缓存前的三问:
1.访问频率高还是低?
考虑一下你的系统访问真的很大吗,真的需要使用缓存?每天业务量很小的系统没有必要设计的太复杂。
虽然引入缓存层能加快访问速度,但是也增加了业务的复杂度。
访问频率高,适合缓存,而且效果也好些;
2.读写比例是什么样的?
分析一下业务的读写比例,系统是读多还是写多的业务。
访问频率高,读多写少,适合缓存,效果会好
3.数据一致性要求高吗?
一般的系统都是数据实时变化的,或者需要一致性的。
使用缓存适用那些对数据一致性要求不高的业务。
3. 缓存最常见的几个问题和解决方案
3.1 缓存穿透
3.1.1 缓存定义
一个比喻,假如防弹衣只保护身体的正面的,你不按套路出牌,子弹是能拐弯的,绕过了防弹衣,打到了身体的后背,防弹衣就相当于没有作用。
请求去查询一条压根儿数据库中根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。
3.1.2 带来的问题
用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
严重的话,会导致数据库直接挂掉。
3.1.3 解决方案:
1.最简单的:及时数据库中不存在的数据也缓存起来
可以为这些不存在 key 对应的值设置为null 丢到缓存里面去。后面再出现查询这个key 的请求的时候,直接返回null
2.高级一些:使用布隆过滤器
在缓存之前在加一层 BloomFilter ,在查询的时候先去 BloomFilter 去查询 key 是否存在,如果不存在就直接返回,存在再走查缓存
方案比较
第一种方案就会缓存大量不存在key的数据;
对于空数据的key有限的,重复率比较高的,我们则可以采用第一种方式进行缓存。
3.2 缓存击穿
3.2.1 定义
比喻:数据库是人,缓存是防弹衣,子弹是请求线程,本来防弹衣是防止子弹打到人身上的,但是当防弹衣遇到了假货,某些部分是空的,里面没有防弹的物质时,子弹就会穿过它,打到人身上.
在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿。
3.2.2 带来的问题
会造成某一时刻数据库请求量过大,压力剧增。
3.2.3 解决方案
1. 后台主动刷新
既然问题出现在某个key失效的问题,那我们只要不让这个key失效就行了,可以后台起一个Cron任务,去主动更新key的过期时间。
比如,一个key是30分钟过期,可以让cron每29分钟执行一次,更改它的过期时间。
2. 检查时更新
在获取缓存值时,可以再请求获取后,修改对应的过期时间。
将缓存key的过期时间一起保存在数值中,在get操作后,将过期时间与当前时间进行对比,块过期时,修改对应的时间字段。
3. 多级缓存
可以使用多套缓存实例保存缓存值。
比如可以采用一级缓存、二级缓存机制,一级失效时间设置短些,二级长些,这样访问一级不存在时,则访问二级。
4. 加锁限制访问
此方案为数据库失效后,使用互斥锁保护对数据库的频繁操作,是第一个失效请求到数据库后,设置缓存值,后续的直接命中缓存,从而保护数据库。
可以参考一下代码:
3.3 缓存雪崩
3.3.1 定义
当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上面。
3.3.2 带来的问题
缓存集中失效,DB 抗不住这么多请求,严重会直接挂掉。
3.3.3 解决方案
1.在发生前,做好缓存的高可用。
比如是使用 Redis,可以使用 主从+哨兵 ,Redis Cluster 来避免 Redis 全盘崩溃的情况
2.事中
本地缓存 :最简单的map,ehcache
限流&熔断机制:常见的Hystrix等技术。
3.事后
开启持久化配置,更快的恢复线上数据。
以上是关于缓存,这么用才真正达到缓存的效果的主要内容,如果未能解决你的问题,请参考以下文章