27 缓存被污染了,该怎么办?

缓存污染是指一些数据当被访问之后就不会在被访问了,或者会长时间内都不会在对其进行访问了,但是这些数据仍然长时间的滞留在 Redis 缓存中,当缓存污染不严重时,造成的影响不会太明显,但是如果缓存污染比较大,就会造成这些数据大量的占用 redis 缓存的内存,使得之后接收到访问其他数据的请求后要将新的数据从数据库中读取写入到缓存中,就必须要对缓存中的数据进行淘汰,然而这些频繁淘汰数据的操作会需要消耗的大量的时间开销,降低了缓存的性能,使得应用层的请求需要大量的访问后端数据库,请求的响应时间增长了。

一、如何解决缓存污染问题?

解决缓存污染问题,最主要的就是将一些之后长时间不会在被访问的数据从缓存中删除,腾出内存空间用户存储应用层频繁访问的数据,然而就需要合适的数据淘汰策略淘汰数据。

二、不同的数据淘汰策略解决缓存污染问题方面的有效程度

(1)volatile-random 和 allkeys-random

由于这两种策略都是随机的筛选数据进行删除,因此在解决缓存污染问题上的效果并不明显。因此无论是从设置了过期时间的数据中还是从所有的键值对中筛选出来的数据本身就是随机性的,被删除的数据就很有可能之后很快就被访问。

(2)volatile-ttl

该策略是在设置了过期时间的键值对中选择最早过期的数据进行删除,虽然不像是上面两种策略一样筛选删除的数据是随机性的,但是最早删除的数据并不能代表之后该数据再次被访问的情况,除非是在业务层已经确定数据在一定时间之后不会在被访问,因此有目标性的设置了过期时间是确认不会再被访问后的时间段,因此使用 valatile-ttl 策略的时候就可以有效的解决缓存污染问题。

(3)LRU 缓存策略

虽然 URL 策略是典型的缓存策略,但是它仅仅只考虑数据最近被访问的时间戳(即:访问时效性),但是如果某个占用大量内存的数据最近被访问一次之后,但是之后不会在对该数据进行访问,之后由于应用层需要访问其他数据,因此就需要读缓存进行“数据更新”,但是由于大量最近被访问但是不会再次被访问的数据占用了大量的内存,因此就仍然无法有效的解决缓存污染的问题。
4、LFU 缓存策略
LFU 缓存策略在 URL 策略的基础上为每个数据添加了一个计数器,用于计算该数据被访问的次数,当使用 LFU 淘汰数据的时候就需要筛选出访问次数最少的数据,如果访问数据次数相同那么就根据 LRU 算法比较数据最近被访问的时间戳,筛选出时间戳最小值的数据,然后进行淘汰。因此在 UFL 淘汰策略中即考虑到了数据的时效性又考虑到了数据被访问的次数。和那些被频繁访问的数据相比,扫描式单次查询的数据因为不会被再次访问,所以它们的访问次数不会再增加。因此,LFU 策略会优先把这些访问次数低的数据淘汰出缓存。这样一来,LFU 策略就可以避免这些数据对缓存造成污染了。

三、LFU 缓存策略的优化

在 LFU 缓存策略中,将数据的 RedisObject 中的 24 bit(3 字节)的 url 字段分成两段,其中前 16 字节用于存储对应数据最近被访问的时间戳信息,后 8 字节用于保存对应数据被访问的次数。但是对于百万级别的访问量中,8 字节只能存储 0~255 个数字,往往是不够用的,因此在 UFL 缓存策略中就对此进行了一个优化,其计数访问次数的规则不是简单的访问一次就进行加一的操作,而是选择了更优化的计数规则。同时当从数据库中读取数据到 Redis 缓存中是,会根据设置的 LFU_INIT_VALUE(lfu_init_value)配置的参数值默认给缓存新增的数据的 RedisObject 中的计数器的值进行一个初始化,默认大小是 5,这样做的目的也是为了避免由于刚存储到 Redis 缓存中的数据由于其访问的次数太小导致很快就从缓存中淘汰出去。

(1)LFU 缓存策略的计数规则

将当前数据的计数器的值乘以 lfu_log_factor(LFU 日志倍数因子),将乘积之后的数据加 1,然后取其计算出来的值的倒数与(0~1)的随机数进行比大小,如果比这个随机数大,那么就对计数器进行加一的操作。

(2)lfu_log_factor 参数设置问题

以下是官网中提供的不同设置的 lfu_log_factor 设置的值对应不同的实际访问的次数,对应的计数器的值的关系图,可以看到的是在面对百,千,万级别的数据访问量,其计数器中的值的区分度已经很明显了,所以一般我们就会将其 lfu_log_factor 的值设置为 10。同样随着应用层中访问的并发量的程度,想区分越高的访问次数就可以将其 lfu_log_factor 的值设置的更大些。
27 缓存被污染了,该怎么办?_第1张图片

(3)lfu 计算器值衰减机制

  • 由于面对复杂的应用负载情况,因此就可能存在当对某些数据进行大量的访问之后,该数据中的计数器的值已经很高了,但是之后又不会在对该数据进行访问,但是由于计数器值的值比较高,使得会滞留在 Redis 缓存中,同样可能会造成缓存污染,因此在 Redis 缓存中的 LFU 缓存策略中添加了计数器衰减机制。
  • LFU 缓存策略中会根据当前的时间与数据最近被访问的时间戳的差值一分钟为单位的值除以 lfu_decay_time (LFU 衰减时间)配置参数的值,其最后计算出来的值就是该数据中计数器要衰减的值。

(4)设置 lfu_decay_time

我们设置的 lfu_decay_time 的时间越大,其数据计数器衰减的值就会变小,因此如果在业务中存在短时的高频访问某个数据的情况下,我们就可以将 lfu_dacy_time 的值设置为 1, 使得让短时间高频访问的数据的访问次数在不再访问的时候尽快的衰减器访问的次数,让该数据从 Redis 缓存中尽快删除,避免造成缓存污染。

你可能感兴趣的:(Redis,核心技术与实战,redis)