关于:Redis 的内存回收策略、Key 失效机制

来自Wikioe
Eijux讨论 | 贡献2021年5月11日 (二) 17:13的版本 →‎Redis 内存设置
跳到导航 跳到搜索


关于

在生产环境我们偶尔会遇到 Redis 服务器内存不够的情况,那对于这种情况 Redis 的内存是如何回收处理的呢?另外对于带有过期时间的 Key Redis 又是如何处理的呢?

Redis 内存设置

如果要设置 Redis 的最大内存大小,依旧可以通过两个方式:

  1. 只需要在配置文件“redis.conf”中配置一行“maxmemory xxx”即可,
    Redis:配置文件设置内存大小.png
    # 设置最大占用内存为100MB
    maxmemory 100mb
    
    • 如果设置为 0 :64位的操作系统默认是没有内存限制,而32位的操作系统隐式限制为 3 GB。
  2. 或者我们通过“config set”命令在运行时动态配置 Redis 的内存大小。
    // 获取最大内存限制
    config get maxmemory
     1)  "maxmemory"
     2)  "0"
    
    // 设置最大的内存限制
    config set maxmemory 100mb
    

内存过期策略

Redis 提供了多种内存过期策略:

  1. volatile-lru”:在“所有带有过期时间的 key”中使用 LRU 算法淘汰数据;【带有过期时间的 key,LRU】
  2. volatile-random”:在“所有带有过期时间的 key”中随机淘汰数据;【带有过期时间的 key,随机】
  3. volatile-ttl”:在“所有带有过期时间的 key”中,淘汰会最早过期的数据;【带有过期时间的 key,最早过期】
  4. alkeys-lru”:在“所有的 key”中使用 LRU 算法淘汰数据;【所有key,LRU】
  5. allkeys-random”:在“所有的 key”中随机淘汰数据;【所有key,随机】
  6. noeviction”:不回收,当达到最大内存的时候,在增加新数据的时候会返回 error,不会清除旧数据;【不淘汰】【默认策略】
  • LRU:“Least Recently Used”,即“最近最少使用”。
  • “volatile-lru”,“volatile-random”,“volatile-ttl”这几种情况(根据过期时间淘汰),在 Redis 中没有带有过期 Key 的时候跟“noeviction”策略是一样的。

配置

在配置文件中我们使用“maxmemory-policy”来配置策略:

Redis:配置文件设置内存过期策略.png


淘汰策略是可以动态调整的,调整的时候是不需要重启的

   “To pick the right eviction policy is important depending on the access pattern of your application, however you can reconfigure the policy at runtime while the application is running, and monitor the number of cache misses and hits using the Redis INFO output in order to tune your setup.”

策略的执行过程

过期策略按照以下步骤执行:

  1. 客户端运行命令,添加数据申请内存;
  2. Redis 检查内存的使用情况,如果已经超过的最大限制,就是根据配置的内存淘汰策略去淘汰相应的 key,从而保证新数据正常添加;
  3. 继续执行命令。

近似的 LRU 算法

Redis 中的 LRU 算法不是精确的 LRU 算法,而是一种经过采样的 LRU。

我们可以通过在配置文件中设置“maxmemory-samples 5”来设置采样的大小(默认值为 5,可以自行调整)。


官方提供的采用对比如下,我们可以看到当采用数设置为 10 的时候已经很接近真实的 LRU 算法了。

Redis:“近似的 LRU 算法”采样对比.png


在 Redis 3.x 以上的版本的中做过优化,目前的近似 LRU 算法以及提升了很大的效率,Redis 之所以不采样实际的 LRU 算法,是因为会耗费很多的内存

The reason why Redis does not use a true LRU implementation is because it costs more memory.

Key 的过期策略

Key 的过期策略,就是带有过期时间的 key

设置带有过期时间的 key

示例:

通过“redis> set name ziyouu ex 100”命令,在 Redis 中设置一个 key 为 name,值为 ziyouu 的数据。
Redis:设置带有过期时间的 key.png

从上面的截图中我们可以看到右下角有个 TTL,并且每次刷新都是在减少的,说明我们设置带有过期时间的 key 成功了。

Redis 如何清除带有过期时间的 key

Redis 清除带有过期时间的 key,有两种方式:

  1. 定时策略:给每个 key 加一个定时器,这样当时间到达过期时间的时候就自动删除 key。
    • 对内存友好(因为可以及时清理过期的 key);但对 CPU 不友好(每个带有过期时间的 key 都需要一个定时器,会占用很多的 CPU);
    • 主动清理。
  2. 惰性策略:在每次访问一个 key 的时候再去判断这个 key 是否到达过期时间了,过期了就删除掉。
    • 对内存不太友好;对 CPU 友好;
    • 被动清理。
    • 但是存在一个问题:如果这些过期的 key 我们再也不会访问,那么永远就不会删除了。


Redis 服务器在真正实现的时候上面的两种方式都会用到,这样就可以得到一种折中的方式。


另外在定时策略中,从官网我们可以看到如下说明:

Specifically this is what Redis does 10 times per second:

1、Test 20 random keys from the set of keys with an associated expire.
2、Delete all the keys found expired.
3、If more than 25% of keys were expired, start again from step 1.

即:Redis 会在有过期时间的 Key 集合中随机 20 个出来,删掉已经过期的 Key,如果比例超过 25%,再重新执行操作。每秒中会执行 10 个这样的操作。