细说Redis-p2(2022.03.20)
上一章我们已经了解了redis是干嘛以及集群等功能以及细节。这一章我们来聊聊缓存的设计和使用redis需要注意的点以及过期数据处理的策略。细说Redis-p21. 多级缓存的设计1.1 Ngnix层1.2 EhCache层1.3 Redis层2. Redis的常见问题2.1 缓存击穿2.2 缓存穿透2.3 缓存雪崩3.Redis对于过期键清除策略3.1被动删除(惰性删除)3.2 主动删除3.3 主
上一章我们已经了解了redis是干嘛以及集群等功能以及细节。这一章我们来聊聊缓存的设计和使用redis需要注意的点以及过期数据处理的策略。
细说Redis-p2
1. 多级缓存的设计
通常来说亿万级流量电商微服务架构如下
让我们一层层的来剖析一下
1.1 Ngnix层
Ngnix是高性能的HTTP和反向代理web服务器,有不是很清楚的同学可以去看看我之前写的Nginx文章,能够让大家对Nginx有一个大致的了解。
对于电商系统来说,比如说双11的时候,肯定会有那种特别火商品,刚开始抢购就会有上万人或者十万、百万人去抢购,比如说:限量的茅台酒、当天折扣的奢侈品等。
对于这些商品,都是热点数据中的热点数据。通常这一类数据,我们都会避免让请求直接打到redis或者web上面,来减轻redis的负担。
流程如下:
1.nginx会找到对应的本地html模板
2.nginx读取本地的缓存中获取数据
3.渲染后形成页面,返回给用户
要知道,这个速度很快,因为全是内存操作
1.2 EhCache层
这里不对 EhCache做过多说明,不清楚的同学可以看看下面两篇帖子
EhCache是什么
EhCache和Redis的区别
简单来说,多级缓存的目的就是为了提速和减轻web的访问压力。不管是我们刚刚提到的使用nginx转发到本地内存或是现在的EhCache,都是为了提高访问的速度。因为你光用redis根本没办法承受如此大的流量冲击
1.3 Redis层
Redis应该是我们作为缓存工具做常见的了,基本上来说就是为访问数据库最后一道拦截了。要知道磁盘和内存的读取速率大约差了4个数量级。都在内存中找要远远好过都在磁盘中找。
mysql的访问不再赘述
总结下:之所以采用这套架构就是为了提高服务的可用性以及尽可能的对读取速度提速
2. Redis的常见问题
2.1 缓存击穿
概念:
简单来说,缓存击穿就是说请求的数据在Redis中找不到(可能这个时刻失效了),导致该请求直接打到数据库中。但是如果在同一时刻出现大量的这种情况,将会导致数据库挂掉。
解决办法:
为了避免同一时刻大量的缓存失效,我们通常在设置过期时间时,加上一个随机时间。这样可以避免同一个时刻大量的缓存失效的情况。
2.2 缓存穿透
概念:
查询一个缓存层和数据库中都不会命中的数据。导致Redis和数据都被击穿
出现这种情况的原因:
1.自身的业务逻辑出现问题或者数据出现问题
2.恶意的攻击
解决方案:
1.空值缓存:
如果出现Redis及数据库中都没有的数据,那么设置一个空值缓存,将其放入我们的内存中(这样可以避免Redis去存这一系列的数据)。
2.我们也可以使用布隆过滤器来更好的解决这个问题
2.3 缓存雪崩
概念:缓存雪崩其实和缓存击穿有些类似,都是指在缓存中找不到数据了。但是缓存雪崩更为可怕,它是指缓存层支撑不住或宕掉后, 大量请求打向后端存储层。
解决方案:
1.保证缓存层服务高可用性,比如使用Redis Sentinel或Redis Cluster。
2. 依赖隔离组件为后端限流熔断并降级。比如使用Sentinel或Hystrix限流降级组件。
3.Redis对于过期键清除策略
3.1 被动删除(惰性删除)
当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期 key
3.2 主动删除
由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key
3.3 主动清理策略
当前已用内存超过maxmemory限定时,触发主动清理策略
主动清理策略在Redis 4.0 之前一共实现了 6 种内存淘汰策略,在 4.0 之后,又增加了 2 种策 略,总共8种
a) 针对设置了过期时间的key做处理:
- volatile-ttl:在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删 除,越早过期的越先被删除。
- volatile-random:就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。
- volatile-lru:会使用 LRU 算法筛选设置了过期时间的键值对删除。
- volatile-lfu:会使用 LFU 算法筛选设置了过期时间的键值对删除。
b) 针对所有的key做处理:
- allkeys-random:从所有键值对中随机选择并删除数据。
- allkeys-lru:使用 LRU 算法在所有数据中进行筛选删除。
- allkeys-lfu:使用 LFU 算法在所有数据中进行筛选删除
c) 不处理:
- noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作。
常见的使用策略
LRU 算法(Least Recently Used,最近最少使用) 淘汰很久没被访问过的数据,以最近一次访问时间作为参考。
LFU 算法(Least Frequently Used,最不经常使用) 淘汰最近一段时间被访问次数最少的数据,以次数作为参考。
4. 布隆过滤器
对于恶意攻击,向服务器请求大量不存在的数据造成的缓存穿透,还可以用布隆过滤器先做一次过滤,对于不存在的数据布隆过滤器一般都能够过滤掉,不让请求再往后端发送。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在(先记住这句话)
布隆过滤器其实就是一个大型的位数组和几个不一样的无偏 hash 函数(所谓无偏就是能够把元素的 hash 值算得比较均匀)。
画重点:它的底层就是由一个很长很长的二进制的数组构成的。
布隆过滤器执行过程:
1.向布隆过滤器中添加key时,会使用多个hash函数对key进行 hash算得一个整数索引值(进行多次hash运算)
2.然后对位数组长度进行取模运算得到一个位置,每个hash函数都会算得一个不同的位置。再把位数组的这几个位置都置为1就完成了add 操作。
3.向布隆过滤器询问 key 是否存在时,跟add一样,也会把 hash的几个位置都算出来,看看位数组中这几个位置是否都为 1,只要有一个位为 0,那么说明布隆过滤器中这个key 不存在。如果都是 1,这并不能说明这个 key 就一定存在,只是极有可能存在。
问题:
-
为什么说当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在呢?
刚刚我们提到了布隆过滤器会将这个key进行多次hash运算,然后将得到的数值和布隆过滤器的长度进行取模,然后将得到的结果在布隆过滤器上找到这个位置,看看这个位置上有没有放数据。
所以说不存在肯定不存在,存在可能不存在的原因则是因为出现hash碰撞导致的。(因为这些位被置为 1 可能是因为其它的 key 存在所致。如果这个位数组 比较稀疏,这个概率就会很大,如果这个位数组比较拥挤,这个概率就会降低) -
布隆过滤器的长度如果设置的很小,那么出现差错的概率不就越大吗?
所以说我们设置长度都是很长很长的。 -
设置的越长,那么占用的空间不就越大吗?
这个不用担心,就算你设置1一个亿的长度,也占用不了多大的空间。因为布隆过滤器是是以位为单位,8个位(bit)才是1个byte。你设置为1一个亿又能占用多大呢?
所以说,使用布隆过滤器要比设置空值缓存好的多。因为如果出现恶意攻击,如果有1千万个不存在的key,那么对于内存或者redis的空间占用是非常大的。但是布隆过滤器的特性,对比下来则占用的空间非常小。
使用的时候要注意:布隆过滤器是不能进行修改的,只能一开始就将数据导入
更多推荐
所有评论(0)