2
  • 把 Redis 当做缓存使用时,有时你可以方便的让它在新数据时自动逐出旧数据。这一点大家都比较清楚,因为 memcached 默认也会这么干

  • Redis 仅支持 LRU 逐出策略。下文主要讲述 Redis maxmemory 指令,这个指令用于限定内存使用量,以及讲述了 Redis 使用到的 LRU 算法,这是一种近似LRU算法。

  • maxmemory 配置指令

    • maxmemory 指令用于限定内存使用量。可以在 redis.conf 文件中设置,也可以通过 CONFIG SET 命令在运行时设置。

    • 例如在 redis.conf 文件中添加如下指令将内存限定在 100M 以内

      • maxmemory 100mb

    • 设置成 0 时表示无限制。64位系统下默认无限制,32位系统则强制指定为 3GB

    • 当内存使用达到限定值时,可以选择几种不同的策略。例如 Redis 可以在调用指令时直接返回错误(这些指令会导致更多内存使用),或者是逐出老数据,给新数据纳出空间,让内存占用保持在限定一下。

  • 逐出策略

    • 具体的逐出策略通过 maxmemory-policy 指令进行配置,主要有如下策略:

      • noeviction:调用某些指令时返回错误(主要是绝大多数的写指令,DEL 和 部分其他指令不包括)

      • allkeys-lru:对全键进行LRU

      • volatile-lru:对指定了过期时间(expire set)的键进行LRU

      • allkeys-random:对全键进行随机逐出

      • volatile-random:对指定了过期时间的键随机逐出

      • volatile-ttl:对指定了过期时间,并且 TTL 较短的键进行逐出

    • volatile-* 系列指令在无键值满足条件时(例如未设置过期时间),表现为 noeviction

    • 不同的应用选择不同的逐出策略,当然你可以根据命中率(INFO指令)在运行时动态调整策略。

    • 可以参考以下的经验法则:

      • allkeys-lru,预期的请求符合长尾理论。或是啥都不懂时配成这个不会太差

      • allkeys-random,会持续轮询所有的键。或者预期的请求符合均匀分布

      • volatile-ttl,在生成缓存对象时指定不同的 ttl 值,所以你得控制好

    • 你在单实例上同时存储缓存数据,以及一些持久化数据时,volatile-lru 和 volatile-random 会比较适合。但是通常建议缓存数据和持久化数据用不同的实例存储。

    • 另外,对一个键设置过期时间会占用额外的内存,所以在内存压力较大时 allkeys-lru 的内存使用率会较好。

  • 逐出过程是如何实现的

    • 最好从以下几个方面来了解逐出过程

      • 客户端运行了一个消耗内存的指令

      • Redis 检查内存占用后发现超限,执行逐出策略

      • 执行一个新的指令,如此循环

    • 即反复的让 Redis 的内存占用在限定值上下波动,来观察和验证逐出策略

    • 当一个指令消耗较多内存时,一定时间范围内可以观察到明显的内存超限

  • 近似LRU算法

    • Redis 使用的 LRU 算法是一个近似实现,即逐出Key并不一定真正访问最少的键。它采用的方式是,对逐出范围内的键进行采样,然后对样本进行逐出。什么鬼。

    • 在 Redis 3.0中有了一些改进,在提升性能的同时,让近似LRU的结果更加接近真实LRU。

    • Redis LRU挺重要的一点是,你可以调整算法精度,即调整每次逐出时的取样数。可以通过这个指令进行调整:

      • maxmemory-samples 5

    • Redis 使用 近似LRU 的目的主要还是为了节省内存,对于应用来说,近似与真实,实际上是等效的。

    clipboard.png

  • 在 Redis 中填充满指定数目的数据,顺序访问所有的键,在LRU下,第一个键是最佳逐出对象。然后增加50%的键值,逐出一半的老数据。

  • 图中的三种点形成了三条不同的条纹

    • 浅灰色表示已经逐出的

    • 灰色表示未被逐出的

    • 绿色表示新增的

  • 理论LRU的结果完全符合预期,前一半的老数据逐出。Redis LRU 则是概率上的逐出老数据。

  • 可以看到,取样数为5时,Redis 3.0 比 Redis 2.8 效果要好很多,2.8逐出了不少刚刚被访问过的数据。取样数为10时,Redis 3.0 的表现跟理论LRU就非常接近了。

  • 如果请求符合长尾法则,那么真实LRU与Redis LRU之间表现基本无差异。

  • 你可以在增加一定CPU消耗的情况下,提高取样数,然后检查命中率是否有变化

  • 在生产环境,通过 CONFIG SET maxmemory-samples <count> 指令可以方便的设置取样数。


小朋友
395 声望11 粉丝