分布式缓存(一)失效策略和缓存问题击穿,雪崩,穿透
缓存失效策略
一般而言,缓存系统中都会对缓存的对象设置一个超时时间,避免浪费相对比较稀缺的缓存资源。对于缓存时间的处理有两种,分别是主动失效和被动失效。
主动失效
主动失效是指系统有一个主动检查缓存是否失效的机制,比如通过定时任务或者单独的线程不断的去检查缓存队列中的对象是否失效,如果失效就把他们清除掉,避免浪费。主动失效的好处是能够避免内存的浪费,但是会占用额外的CPU时间。
被动失效
被动失效是通过访问缓存对象的时候才去检查缓存对象是否失效,这样的好处是系统占用的CPU时间更少,但是风险是长期不被访问的缓存对象不会被系统清除。
缓存淘汰策略
缓存淘汰,又称为缓存逐出(cache replacement algorithms或者cache replacement policies),是指在存储空间不足的情况下,缓存系统主动释放一些缓存对象获取更多的存储空间。
对于大部分内存型的分布式缓存(非持久化),淘汰策略优先于失效策略,一旦空间不足,缓存对象即使没有过期也会被释放。这里只是简单介绍一下,相关的资料都很多,一般LRU用的比较多,可以重点了解一下。
FIFO
先进先出(First In First Out)是一种简单的淘汰策略,缓存对象以队列的形式存在,如果空间不足,就释放队列头部的(先缓存)对象。一般用链表实现。
LRU
最近最久未使用(Least Recently Used),这种策略是根据访问的时间先后来进行淘汰的,如果空间不足,会释放最久没有访问的对象(上次访问时间最早的对象)。比较常见的是通过优先队列来实现。
LFU
最近最少使用(Least Frequently Used),这种策略根据最近访问的频率来进行淘汰,如果空间不足,会释放最近访问频率最低的对象。这个算法也是用优先队列实现的比较常见。
分布式缓存的常见问题
缓存穿透
- DB中不存在数据,每次都穿过reids缓存查DB,造成DB的压力。一般是网络攻击(库中没有数据,但是一直有请求获取,每次都穿过缓存和数据库)
- 解决方案:
- 接口层增加校验,如用户鉴权校验,id做基础校验,无效数据直接拦截如(id<=0);
- 放入一个特殊对象,在redis中存入一个固定的值,设置过期实现(避免下次数据库中有redis中没有)(比如特定的无效对象不适合key是不确定的,redis就会存在大量无效key)
- 布隆过滤器实现(BitMap原理:1.将key经过多次hash映射函数,得到下标值 2.将数据库中的Hash(key)存入二进制位数组中 )查看key是否在BitMap中存在,存在则查询redis,不存在直接返回,缺点:1.存在一定的hash碰撞,如何解决碰撞:1)扩大数组长度,比如100个长度存储30个数据,缺点空间浪费 2) 将同一个key多次hash减少碰撞,不能保证100%无碰撞 2.不适用于频繁删除key(比如数据库中频繁删除缓存的这个数据,布隆过滤器不提供删除方法,原因是避免hash碰撞)如有频繁删除情况可以考虑布谷鸟过滤器,布隆过滤器算法 谷歌的jar Guava中有相关现成的算法)
布隆过滤器算法:
本质:位数组,一系列随机函数映射
查找B,返回:1,1,1, 不一定存在,查找E,返回1,1,0则一定不存在
如果布隆过滤器判断元素在集合中存在,则不不一定存在,如果判断不存在,则一定不存在
一亿个数据如何快速查找某一个数字?
缓存击穿
- 缓存没有数据,DB有数据据 (热点数据redis缓存中只存储了一条数据,这个数据过期了,这个时候大量并发请求透过redis没有获取到又访问数据库),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
-
- 解决方案:
- 一般公司不需要解决,只是一条热门数据,并发量不是特别大的时候访问一条数据不会使数据库瘫痪
- 设置热点数据永远不过期
- 更新缓存时使用分布式锁锁住服务,防止请求穿透直达DB,查DB得到数据同时存入缓存,都成功释放锁(保证同一时刻只有一个请求打向数据库,多个请求只有获取锁的请求读取数据库然后存入redis,后续其他请求从redis中获取数据,吞吐量不高)
-
-
少量并发请求直接查询数据库,然后存数据到redis中,允许有一部分请求到数据库比如有100个请求进入数据库,那么101个请求就可能是从redis中获取的
缓存雪崩
- 大量缓存设置了相同的失效时间,缓存的数据,在某一时间突然失效(无法访问)导致大量的请求打向MySQL数据库
同一时间失效或者无法访问,造成服务瞬间性能急剧下降 - 解决方案:
- 1.同时失效:缓存时间使用基本时间加上随机时间
- 2.无法访问:redis挂了,可以考虑集群部署(将key分片存储,一台挂了还有另外redis可供使用),主从分布式部署。将热点数据均匀分布在不同机器上使得缓存数据库分布在各个redis中。