初识 将Redis作为LRU缓存


Redis用作缓存时,通常很容易在添加新数据的同时移除旧数据。 此行为在开发者社区中是众所周知的,因为它是memcached system 的默认行为。

LRU(Least Recently Used,最近最少使用),将最近最少使用的数据删除掉。

Redis 4.0 开始引入了LFU(Least Frequntly Used,最不常用)淘汰策略。

1. Maxmemory配置

Redis maxmemory 用于将内存使用限制为某一固定量。该配置常在名为redis.conf 的文件中,或者在运行时(runtime)使用CONFIG SET命令进行配置。

例如,为了配置内存限制为100 MB,可以在 redis.conf 文件中使用以下设置。

maxmemory 100mb

maxmemory 设置为零则没有内存限制。 这是64位系统的默认行为,而32位系统使用3GB的隐式内存限制。

当达到限定的内存量时,可以选择不同的策略。 只有当 Redis 执行的命令要使用更多的内存,Redis 才会返回error,或者Redis删除一些旧数据,以便在每次添加新数据时返回到指定的限制。

2. 淘汰策略

在配置文件里使用 maxmemory-policy 命令可以指定以下淘汰策略:

noeviction:在达到内存限制并且client尝试执行可能导致使用更多内存的命令时返回错误。
allkeys-lru:尝试先删除LRU的key。
volatile-lru:尝试先删除LRU的key,要求删除的这个key必须已经过期。
allkeys-random:随机删除key。
volatile-random:随机删除key,要求删除的这个key必须已经过期。
volatile-ttl:删除已经过期的key,尝试先删除较短生存时间(TTL)的key。

如果执行这些策略时,发现没有与条件相匹配的key,则volatile-lruvolatile-randomvolatile-ttl策略的行为类似于noeviction

选择正确的淘汰策略很重要,具体取决于应用程序的访问方式,也可以在应用程序运行时在运行时重新配置该策略,为了方便调整设置,可以使用RedisINFO 命令来监控缓存未命中和命中的数量。

一般而言,根据经验:

  • 使用allkeys-lru策略。如果你希望request呈指数分布,也就是说,你希望对于某些元素的访问比其他元素多得多。
  • 使用allkeys-random。如果你希望对所有的key进行行周期性第连续访问,或者当你期望分布是统一的(所有元素以相同的概率被访问)。
  • 使用volatile-ttl。如果你希望能够在创建缓存对象时通过使用不同的TTL值向Redis 表明哪些key是最佳过期候选者。

当你要使用单个Redis实例进行缓存并拥有一些持久化的key时,volatile-lruvolatile-random策略相当有用。 但是,最好运行两个Redis实例来解决此问题。

值得注意的是,为一个key设置过期时间要耗费内存,因此像allkeys-lru这样的策略能提高内存效率,因为不需要为那个在内存压力下需要被删除的key设置过期时间。

3. 淘汰策略如何工作

理解淘汰策略的工作工程时很关键的。

  • client 运行新命令,从而添加更多数据。
  • Redis会检查内存使用情况,如果大于maxmemory限制,则会根据策略删除key。
  • 执行新命令,依此类推。

所以内存使用量会一直在maxmemory上下徘徊,如果某个命令要求添加一个很大的数据很可能造成redis使用的内存明显超过了maxmemory限制。

4. 近似LRU算法

redisLRU没有严格的实现LRU,这意味着redis不是淘汰最佳(最久没访问)的数据。。RedisLRU算法进行近似处理,方法是对少量key进行采样,然后从采样的key中删除掉访问时间最早的key。

3.0以后redis会使用备选池做淘汰,提升了性能,准确性更高,更接近LRU算法(代码里提升性能很明显,准确率更高这点看不出来,可能官方做统计得出的结论)。可以设置样本大小调整算法的准确率。

maxmemory-samples 5

Redis之所以不使用真正的LRU实现,是因为它占用更多内存(要遍历排序,会慢很多)。

5. LFU模式

从4.0开始redis引入了一个新的淘汰模型LFU(Least Frequently Used)。一些情况下这个模型在命中率上更会准确。LFU会统计数据的使用率,使用率低的会被淘汰,使用率高的留下。LRU会保留最近访问了但是平常访问率很低的数据,风险就是淘汰了一个平常访问率高但是最近没访问的数据。 LFU不会存在这样的问题,所以LFU更适用于各种不同的访问模型。LFU策略配置如下:

  • volatile-lfu:在设置了过期时间的数据里使用近似LFU淘汰算法。
  • allkeys-lfu:在所有的数据上使用LFU淘汰算法。

LFULRU类似也是一种概率计算,LFU使用一个叫morris counter的概率统计方法,一个数据只使用几个比特。和一个叫过期时间(decay period)的数结合使用。统计值(counter)随着时间减小。LFU也是使用采样的方式淘汰数据。LFU有更多的调整选项,4.0默认的配置

  • 一百万访问量会使统计值(counter)变为最大
  • 衰败期是一分钟

这些是经过测试比较好用的,用户也可以自己设置。配置命令如下:

lfu-log-factor 10
lfu-decay-time 1

一个比较特殊的用法是衰败期设置成0,每次统计都会衰败,这是个比较少用的方法。指数因子用来指定多大的访问量会是统计值变为最大,统计值范围0-255。指数因子越大需要越多的访问量使统计值变为最大,指数因子越小访问量低的时候分辨率越高。

+--------+------------+------------+------------+------------+------------+
| factor | 100 hits   | 1000 hits  | 100K hits  | 1M hits    | 10M hits   |
+--------+------------+------------+------------+------------+------------+
| 0      | 104        | 255        | 255        | 255        | 255        |
+--------+------------+------------+------------+------------+------------+
| 1      | 18         | 49         | 255        | 255        | 255        |
+--------+------------+------------+------------+------------+------------+
| 10     | 10         | 18         | 142        | 255        | 255        |
+--------+------------+------------+------------+------------+------------+
| 100    | 8          | 11         | 49         | 143        | 255        |
+--------+------------+------------+------------+------------+------------+

6. 参考文献

Redis 官方文档 Using Redis as an LRU cache
LRU缓存机制
用redis当作LRU缓存

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章