IT评测·应用市场-qidao123.com技术社区

标题: Redis 内存管理 [打印本页]

作者: 我可以不吃啊    时间: 2024-12-11 02:23
标题: Redis 内存管理
Redis 给缓存数据设置过期时间有什么用?

一样平常环境下,我们设置保存的缓存数据的时候都会设置一个过期时间。为什么呢?
内存是有限且贵重的,如果不对缓存数据设置过期时间,那内存占用就会一直增长,终极大概会导致 OOM 问题。通过设置公道的过期时间,Redis 会自动删除临时不须要的数据,为新的缓存数据腾出空间。
Redis 自带了给缓存数据设置过期时间的功能,比如:
  1. 127.0.0.1:6379> expire key 60 # 数据在 60s 后过期
  2. (integer) 1
  3. 127.0.0.1:6379> setex key 60 value # 数据在 60s 后过期 (setex:[set] + [ex]pire)
  4. OK
  5. 127.0.0.1:6379> ttl key # 查看数据还有多久过期
  6. (integer) 56
复制代码
留意 ⚠️:Redis 中除了字符串类型有本身独有设置过期时间的命令 setex 外,其他方法都须要依靠 expire 命令来设置过期时间 。别的, persist 命令可以移除一个键的过期时间。
过期时间除了有助于缓解内存的斲丧,尚有什么其他用么?
很多时候,我们的业务场景就是须要某个数据只在某一时间段内存在,比如我们的短信验证码大概只在 1 分钟内有效,用户登录的 Token 大概只在 1 天内有效。
如果使用传统的数据库来处理的话,一样平常都是本身判断过期,如许更贫苦而且性能要差很多。
Redis 是怎样判断数据是否过期的呢?

Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。

过期字典是存储在 redisDb 这个布局里的:
  1. typedef struct redisDb {
  2.     ...
  3.     dict *dict;     //数据库键空间,保存着数据库中所有键值对
  4.     dict *expires   // 过期字典,保存着键的过期时间
  5.     ...
  6. } redisDb;
复制代码
在查询一个 key 的时候,Redis 首先检查该 key 是否存在于过期字典中(时间复杂度为 O(1)),如果不在就直接返回,在的话须要判断一下这个 key 是否过期,过期直接删除 key 然后返回 null。
Redis 过期 key 删除计谋相识么?

如果假设你设置了一批 key 只能存活 1 分钟,那么 1 分钟后,Redis 是怎么对这批 key 进行删除的呢?
常用的过期数据的删除计谋就下面这几种:
Redis 采用的那种删除计谋呢?
Redis 采用的是 定期删除+惰性/懒汉式删除 联合的计谋,这也是大部分缓存框架的选择。定期删除对内存更加友好,惰性删除对 CPU 更加友好。两者各有千秋,联合起来使用既能兼顾 CPU 友好,又能兼顾内存友好。
下面是我们详细先容一下 Redis 中的定期删除详细是怎样做的。
Redis 的定期删除过程是随机的(
  1. #define ACTIVE_EXPIRE_CYCLE_FAST_DURATION 1000 /* Microseconds. */
  2. #define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* Max % of CPU to use. */
  3. #define ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 10 /* % of stale keys after which
  4.                                                    we do extra efforts. */
复制代码
周期性地随机从设置了过期时间的 key 中抽查一批),以是并不包管所有过期键都会被立刻删除。这也就表明了为什么有的 key 过期了,并没有被删除。而且,Redis 底层会通过限定删除操纵执行的时长和频率来减少删除操纵对 CPU 时间的影响。
别的,定期删除还会受到执行时间和过期 key 的比例的影响:

Redis 7.2 版本的执行时间阈值是 25ms,过期 key 比例设定值是 10%
  1. #define ACTIVE_EXPIRE_CYCLE_FAST_DURATION 1000 /* Microseconds. */
  2. #define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* Max % of CPU to use. */
  3. #define ACTIVE_EXPIRE_CYCLE_ACCEPTABLE_STALE 10 /* % of stale keys after which
  4.                                                    we do extra efforts. */
复制代码
每次随机抽查数量是多少?
expire.c中界说了每次随机抽查的数量,Redis 7.2 版本为 20 ,也就是说每次会随机选择 20 个设置了过期时间的 key 判断是否过期。
  1. #define ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOP 20 /* Keys for each DB loop. */
复制代码
怎样控制定期删除的执行频率?
在 Redis 中,定期删除的频率是由 hz 参数控制的。hz 默以为 10,代表每秒执行 10 次,也就是每秒钟进行 10 次实验来查找并删除过期的 key。
hz 的取值范围为 1~500。增大 hz 参数的值会提拔定期删除的频率。如果你想要更频繁地执行定期删除任务,可以适当增加 hz 的值,但这会加 CPU 的使用率。根据 Redis 官方建议,hz 的值不建议超过 100,对于大部分用户使用默认的 10 就足够了。
下面是 hz 参数的官方注释,我翻译了此中的告急信息(Redis 7.2 版本)。

雷同的参数尚有一个 dynamic-hz,这个参数开启之后 Redis 就会在 hz 的底子上动态盘算一个值。Redis 提供并默认启用了使用自适应 hz 值的本领,
这两个参数都在 Redis 设置文件 redis.conf中:
  1. # 默认为 10
  2. hz 10
  3. # 默认开启
  4. dynamic-hz yes
复制代码
多提一嘴,除了定期删除过期 key 这个定期任务之外,尚有一些其他定期任务例如关闭超时的客户端毗连、更新统计信息,这些定期任务的执行频率也是通过 hz 参数决定。
为什么定期删除不是把所有过期 key 都删除呢?
如许会对性能造成太大的影响。如果我们 key 数量非常庞大的话,挨个遍历检查黑白常耗时的,会严重影响性能。Redis 筹划这种计谋的目标是为了均衡内存和性能。
为什么 key 过期之后不立马把它删掉呢?如许不是会浪费很多内存空间吗?
因为不太好办到,或者说这种删除方式的资本太高了。如果我们使用延迟队列作为删除计谋,如许存在下面这些问题:
大量 key 集中过期怎么办?

当 Redis 中存在大量 key 在同一时间点集中过期时,大概会导致以下问题:

为了避免这些问题,可以采取以下方案:
Redis 内存淘汰计谋相识么?

   干系问题:MySQL 里有 2000w 数据,Redis 中只存 20w 的数据,怎样包管 Redis 中的数据都是热点数据?
  Redis 的内存淘汰计谋只有在运行内存到达了设置的最大内存阈值时才会触发,这个阈值是通过redis.conf的maxmemory参数来界说的。64 位操纵体系下,maxmemory 默以为 0 ,表示不限定内存大小。32 位操纵体系下,默认的最大内存值是 3GB。
你可以使用命令 config get maxmemory 来查看 maxmemory的值。
  1. config get maxmemory
  2. maxmemory
  3. 0
复制代码
Redis 提供了 6 种内存淘汰计谋:
4.0 版本后增加以下两种:

  • volatile-lfu(least frequently used):从已设置过期时间的数据集(server.db.expires)中挑选最不常常使用的数据淘汰。
  • allkeys-lfu(least frequently used):从数据集(server.db.dict)中移除最不常常使用的数据淘汰。
allkeys-xxx 表示从所有的键值中淘汰数据,而 volatile-xxx 表示从设置了过期时间的键值中淘汰数据。
config.c中界说了内存淘汰计谋的枚举数组:
  1. configEnum maxmemory_policy_enum[] = {
  2.     {"volatile-lru", MAXMEMORY_VOLATILE_LRU},
  3.     {"volatile-lfu", MAXMEMORY_VOLATILE_LFU},
  4.     {"volatile-random",MAXMEMORY_VOLATILE_RANDOM},
  5.     {"volatile-ttl",MAXMEMORY_VOLATILE_TTL},
  6.     {"allkeys-lru",MAXMEMORY_ALLKEYS_LRU},
  7.     {"allkeys-lfu",MAXMEMORY_ALLKEYS_LFU},
  8.     {"allkeys-random",MAXMEMORY_ALLKEYS_RANDOM},
  9.     {"noeviction",MAXMEMORY_NO_EVICTION},
  10.     {NULL, 0}
  11. };
复制代码
你可以使用 config get maxmemory-policy 命令来查看当前 Redis 的内存淘汰计谋。

  1. > config get maxmemory-policy
  2. maxmemory-policy
  3. noeviction
复制代码
可以通过config set maxmemory-policy 内存淘汰计谋 命令修改内存淘汰计谋,立刻收效,但这种方式重启 Redis 之后就失效了。修改 redis.conf 中的 maxmemory-policy 参数不会因为重启而失效,不外,须要重启之后修改才气收效。
  1. maxmemory-policy noeviction
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4