1、基础说明
当redis设置内存使用限制后,当达到内存限制时,Redis将尝试删除key(控制节点的最大使用内存)
redis.conf中配置项
maxmemory <bytes>
或者控制台执行
CONFIG SET maxmemory 4gb
,设置内存
参数说明:
- maxmemory的默认值是0,也就是不限制内存的使用。
- 32bit系统如果使用默认配置或配置为maxmemory 0则最大使用3G内存。
- maxmemory的值没有最小限制(但是如果低于1MB,会打一条WARNING日志)。
- 如果设置了maxmemory选项(值 >= 1),redis在接收命令时总是会判断当前是否已经超出最大内存限制,如果超过限制会根据驱逐策略去释放内存(如果是同步释放且释放内存很大,则会阻塞其他命令的执行)。
- 单位,默认字节B,支持,KB、MB、GB、K(1000B)、M(1000000B)、G(1000000000B)
推荐设置方案(需要结合
应用数据实际访问特征
和
成本开销
来综合考虑的。)
-
根据“八二原理”,最常被访问的 20% 的数据来说,它们贡献的访问量,既有可能超过 80%,也有可能不到 80%。
建议把缓存容量设置为总数据量的 15% 到 30%,兼顾访问性能和内存空间开销。
2、淘汰策略
缓存被写满是不可避免的。一共有7种淘汰策略,1种拒绝策略:
-
针对设置过期时间的键值对:即使缓存没有写满,这些数据如果过期了,也会被删除。
除。当然,如果它的过期时间到了但未被策略选中,同样也会被删除。-
volatile-random
:从设置了过期时间的键值对中,进行
随机删除
-
volatile-ttl
:从设置了过期时间的键值对中,根据
过期时间的先后进行删除,越早过期的越先被删除
-
volatile-lru
:从设置了过期时间的键值对中,使用
LRU
算法筛选, -
volatile-lfu
:从设置了过期时间的键值对中,使用
LFU
算法筛选,在 LRU算法的基础上,同时考虑了
数据的访问时效性和数据的访问次数
-
-
所有键值对
-
allkeys-random
:从所有键值对中,随机选择并删除数据; -
allkeys-lru
:从所有键值对中,使用
LRU
算法筛选, -
allkeys-lfu
:从所有键值对中,使用
LFU
算法筛选,
-
-
noevction
:不进行数据淘汰。
一旦缓存被写满了,再有写请求来时,Redis不再提供服务,而是直接返回错误
。
如果一个键值对被删除策略选中了,即使它的过期时间还没到,也需要被删。
设置过期key的方式EXPIRE、PEXPIRE、EXPIREAT、PEXPIREAT
-
剩余时间
- EXPIRE(秒级)、PEXPIRE(毫秒级)
-
指定过期时间戳
- EXPIREAT(设置秒级)、PEXPIREAT(设置毫秒级)
2.1、LRU算法:最近最少使用的原则
LRU 算法的全称是 Least Recently Used,按照
最近最少使用的原则
来筛选数据,最不常用的数据会被筛选出来,而最近频繁使用的数据会留在缓存中。维护一个链表,链表头是MRL(最常使用的数据),链表尾就是LRU(最不常使用的数据)。LRU需要用链表管理所有的缓存数据,这会带来额外的空间开
销,当有数据被访问时,需要在链表上把该数据移动到 MRU 端,如果有大量数据被访问,就会带来很多链表移动操作,会很耗时
Redis 中,LRU算法被做了简化,以减轻数据淘汰对缓存性能的影响。Redis 默认会记录每个数据的最近一次
访问的时间戳
(由键值对数据结构RedisObject 中的 lru 字段记录)。
-
Redis在决定淘汰的数据时,第一次会
随机选出N 个数据
,把它们作为一个候选集合。 - Redis 会比较这 N 个数据的 lru 字段,把lru 字段值最小的数据从缓存中淘汰出去。
-
当需要再次淘汰数据时,Redis 需要挑选数据进入第一次淘汰时创建的候选集合。挑选标准是:
-
能进入候选集合的数据的 lru 字段值
必须小于候选集合中最小的 lru 值。
- 有新数据进入候选数据集后,如果候选数据集中的数据个数达到了 maxmemory-samples,Redis 就把候选数据集中 lru 字段值最小的数据淘汰出去。
-
能进入候选集合的数据的 lru 字段值
Redis 提供了一个配置参数 maxmemory-samples,这个参数就是 Redis 选出的数据个数N。例如,执行如下命令,可以让 Redis 选出 100 个数据作为候选数据集:
CONFIG SET maxmemory-samples 100
2.2、LFU算法
LFU 策略中会从两个维度来筛选并淘汰数据:
- 一是,数据访问的时效性(访问时间离当前时间的远近);
- 二是,数据的被访问次数。
LFU 缓存策略是在 LRU 策略基础上,为每个数据增加了
一个计数器
,来统计这个数据的访问次数。当使用 LFU 策略筛选淘汰数据时:
-
首先会根据数据的
访问次数
进行筛选,把访问次数最低的数据淘汰出缓存。 -
如果两个数据的访问次数相同,LFU 策略再
比较这两个数据的访问时效性
,把距离上一次访问时间更久的数据淘汰出缓存。 -
如果一个key的计数器值特别大,但是长时间没有被访问,redis中LFU算法会有对应的衰减机制
- lfu_log_factor衰减因子:控制计数器值增加的速度,避免 counter(8bit) 值很快就到 255 了。
-
lfu_decay_time默认1:如果数据在 N 分钟内没有被访问,那么它的访问次数就要减 N。
LRU 策略更加关注数据的时效性,而 LFU 策略更加关注数据的访问频次。
3、淘汰策略使用
-
优先使用 allkeys-lru 策略。可以充分利用 LRU 这一经典缓存算法的优势,把最近最常访问的数据留在缓存中,提升应用的访问性能。如果
业务数据中有明显的冷热数据区分
,建议使用
allkeys-lru
策略。 -
如果业务应用中的数据访问频率相差不大,没有明显的冷热数据区分
,建议使用
allkeys-random
策略,随机选择淘汰的数据就行。 -
如果业务中
有置顶的需求
,比如置顶新闻、置顶视频,那么,可以使用
volatile-lru
策略,同时不给这些置顶数据设置过期时间。这样一来,这些需要置顶的数据一直不会被删除,而其他数据会在过期时根据 LRU规则进行筛选。
4、缓存污染
在一些场景下,有些数据被访问的次数非常少,甚至只会被访问一次。当这些数据服务完访问请求后,如果还继续留存在缓存中的话,就只会白白占用缓存空间。这种情况,就是缓存污染。
当缓存污染不严重时,只有少量数据占据缓存空间,此时,对缓存系统的影响不大。但是,缓存污染一旦变得严重后,就会有大量不再访问的数据滞留在缓存中。如果这时数据占满了缓存空间,我们再往缓存中写入新数据时,就需要先把这些数据逐步淘汰出缓存,这就会引入额外的操作时间开销,进而会影响应用的性能。
要解决缓存污染问题,最关键的技术点就是
能识别出这些只访问一次或是访问次数很少的数据
,在淘汰数据时,优先把它们筛选出来并淘汰掉。所以采用LFU策略
- volatile-lfu
- allkeys-lfu