Redis企业级的缓存设计,缓存穿透,缓存击穿原理解释

2020-01-25  本文已影响0人  javap

缓存的收益与成本

①收益

缓存更新策略

内存溢出淘汰策略

当Redis所用内存达到maxmemory上限(used_memory>maxmemory)时会触发相应的溢出控制策略。具体策略受maxmemory-policy参数控制。
Redis支持6种策略:
1)noeviction:默认策略,不会删除任何数据,拒绝所有写入操作并返回客户端错误信息(error)OOM command not allowed when used memory,此时Redis只响应读操作。
2)volatile-lru:根据LRU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。
3)volatile-random:随机删除过期键,直到腾出足够空间为止。
4)allkeys-lru:根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。
5)allkeys-random:随机删除所有键,直到腾出足够空间为止。
6)volatile-ttl:根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略


内存溢出控制策略可以采用config set maxmemory-policy{policy}动态配置。
写命令导致当内存溢出时会频繁执行回收内存成本很高,如果Redis有从节点,回收内存操作对应的删除命令会同步到从节点,导致写放大的问题。


过期删除
应用方更新

a、应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。



b、先删除缓存,再更新数据库
这个操作有一个比较大的问题,更新数据的请求在对缓存删除完之后,又收到一个读请求,这个时候由于缓存被删除所以直接会读库,读操作的数据是老的并且会被加载进入缓存当中,后续读请求全部访问的老数据。
c、先更新数据库,再删除缓存(推荐)
为什么不是写完数据库后更新缓存?主要是怕两个并发的写操作导致脏数据。

缓存粒度

通用性
缓存全部数据比部分数据更加通用,但从实际经验看,很长时间内应用只需要几个重要的属性。
占用空间
缓存全部数据要比部分数据占用更多的空间,存在以下问题:

缓存穿透

缓存穿透是指查询一个根本不存在的数据,缓存层和持久层都不会命中,通常出于容错的考虑,如果从持久层查不到数据则不写入缓存层。

缓存穿透示意图
缓存穿透将导致不存在的数据每次请求都要到持久层去查询,失去了缓存保护后端持久的意义。
缓存穿透问题可能会使后端存储负载加大,由于很多后端持久层不具备高并发性,甚至可能造成后端存储宕掉。通常可以在程序中统计总调用数、缓存层命中数、如果同一个Key的缓存命中率很低,可能就是出现了缓存穿透问题。
造成缓存穿透的基本原因有两个。第一,自身业务代码或者数据出现问题,第二,一些恶意攻击、爬虫等造成大量空命中。
①缓存空对象

缓存空对象会有两个问题:第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间,比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为5分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。
②布隆过滤器拦截
在访问缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来,做第一层拦截,当收到一个对key请求时先用布隆过滤器验证是key否存在,如果存在在进入缓存层、存储层。可以使用bitmap做布隆过滤器。这种方法适用于数据命中不高、数据相对固定、实时性低的应用场景,代码维护较为复杂,但是缓存空间占用少。
布隆过滤器实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
算法描述:

缓存雪崩

由于缓存层承载着大量请求,有效地保护了存储层,但是如果缓存层由于某些原因
不可用或者大量缓存由于超时时间相同在同一时间段失效,大量请求直接到达存储层,存储层压力过大导致系统雪崩。


解决方案:

缓存击穿

系统中存在以下两个问题时需要引起注意:

上一篇下一篇

猜你喜欢

热点阅读