能坚持别人不能坚持的, 才能拥有别人未曾拥有的.
首先看俩问题, 然后针对这俩问题, 整理一下 Redis 过期策略. 如果你对 Redis 的过期策略还不了解, 那么请继续.
1, 我往 Redis 里写的数据怎么没了?
使用 Redis 的同学你要明白一点, 你为什么用 Redis? 用 Redis 的作用是什么? 用 Redis 的好处是什么? 凡事多思考一下为什么, 多想想背后的原因.
就在不久前有朋友跟我说过, 说他们生产环境的 Redis 怎么经常会丢掉一些数据? 写进去了, 过一会儿可能就没了. 我的天啊, 你问这个问题就说明 Redis 你就没用对啊. Redis 是缓存, 你给当存储了用了是吧?
首先要明白一点啥叫缓存? 为啥用缓存?
Redis 是用内存当缓存的. 内存是无限的吗? 相反, 内存是很宝贵而且是有限的, 磁盘是廉价而且是大量的. 可能一台机器就几十个 G 的内存, 但是可以有几个 T 的硬盘空间. Redis 主要是基于内存来进行高性能, 高并发的读写操作的.
那既然内存是有限的, 比如 Redis 就只能用 10 个 G, 你一直往里面写数据, 一直写一直写最后 10 个 G 都用的差不多了, 你还写会, 你想想会发生什么? 当然会干掉一些的数据了, 然后就保留 10 个 G 的数据. 你说会不会造成数据丢失?
那 Redis 会干掉哪些数据? 保留哪些数据呢? 当然是干掉不常用的数据, 保留常用的数据了.
所以说, 这是缓存的一个最基本的概念: 数据是会过期的. 要么是你自己设置个过期时间, 要么是 Redis 自己给干掉.
所以你的 Redis 如果使用不当, 把生产数据存到里面, 又没有去持久化到 MySQL, 那就会有丢失的可能.
2, 我的数据明明都过期了, 怎么还占用着内存啊?
还有一种就是如果你给 key 设置好了一个过期时间, 你知道到一定的时间再去查这个 key 就没有了, 但是你知道 Redis 是怎么给你弄成过期的吗? 什么时候删除掉?
如果你不知道, 在实际的使用过程中你就可能会发现这么一个问题: 为啥好多数据明明应该过期了, 结果发现 Redis 内存占用还是很高? 那是因为你不知道 Redis 是怎么删除那些过期 key 的.
举例, Redis 内存一共是 10 个 G, 你现在往里面写了 5 个 G 的数据, 然后你对这些数据全都设置了 10 分钟之后过期, 结果 10 分钟之后, 你再来查看看, Redis 的内存使用率怎么还是 50% 呢? 5 个 G 的数据都过期了, 我从 Redis 里查, 是查不到了, 结果过期的数据为啥还占用着 Redis 的内存呢.
如果你连这个问题都不知道, 上来就懵了, 回答不出来, 建议你使用 Redis 之前多做做功课, 不然你写代码的时候, 想当然的认为写进 Redis 的数据就一定会存在, 后面导致系统各种漏洞和 bug, 就不好弄了.
3, 问题剖析
(1)设置过期时间
set key value 过期时间 (1 小时) 表示 set 进去的 key,1 小时之后就没了, 就失效了.
我们 set key 的时候, 都可以给一个 expire time, 就是过期时间, 指定这个 key 比如说只能存活 1 个小时? 10 分钟? 这个很有用, 我们自己可以指定缓存到期就失效.
如果假设你设置一批 key 只能存活 1 个小时, 那么接下来 1 小时后, Redis 是怎么对这批 key 进行删除的?
答案是: 定期删除 + 惰性删除
所谓定期删除, 指的是 Redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key, 检查其是否过期, 如果过期就删除.
为什么是随机抽取?
假设 Redis 里放了 10 万个 key, 都设置了过期时间, 你每隔几百毫秒, 就检查 10 万个 key, 那 Redis 基本上就死了, 因为这样 CPU 负载会很高的, 全都消耗在你的检查过期 key 上了.
所以这里可不是每隔 100ms 就遍历所有的设置过期时间的 key,Redis 如果设置成检查所有 Key 那将是一场性能上的灾难. 所以实际上 Redis 是每隔 100ms 随机抽取一些 key 来检查和删除的.
但是问题是, 随机抽取检测 key 是否过去会导致定期删除策略可能会导致很多过期 key 到了时间并没有被删除掉, 那咋整呢? 所以 Redis 还有另一个策略就是惰性删除.
惰性删除 就是说, 在你获取某个 key 的时候, Redis 会检查一下 , 这个 key 如果设置了过期时间那么是否过期了? 如果过期了此时就会删除, 不会给你返回任何东西.
所以并不是 key 到时间就被删除掉, 而是你查询这个 key 的时候, Redis 再懒惰的检查一下.
通过上述两种手段, 保证过期的 key 一定会被干掉.
那么刚才的问题就不难理解了, 就是说, 你的过期 key, 靠定期删除没有被删除掉, 还停留在内存里, 占用着你的内存呢, 除非你的系统去查一下那个 key, 才会被 Redis 给删除掉. 如果都过期了, 定期删除才删了一点点, 而你又没有去查, 没有触发惰性删除, 那么短时间内你的 Redis 内存占用率还是会下不来.
但是实际上这还是有问题的, 如果定期删除漏掉了很多过期 key, 然后你也没及时去查, 也就没走惰性删除, 此时会怎么样? 如果大量过期 key 堆积在内存里, 导致 Redis 内存块耗尽了, 咋整?
别担心 Redis 还有方案: 内存淘汰机制.
(2)内存淘汰策略
如果 Redis 的内存占用过多的时候, 此时会进行内存淘汰, Redis 提供如下丰富的可选策略:
1)noeviction: 当内存不足以容纳新写入数据时, 新写入操作会报错.
(这个一般没人用吧, 实在是太恶心了)
2)allkeys-lru: 当内存不足以容纳新写入数据时, 在所有键空间中, 移除最近最少使用的 key
(这个是最常用的)
3)allkeys-random: 当内存不足以容纳新写入数据时, 在所有键空间中, 随机移除某个 key.
(这个一般没人用吧, 为啥要随机, 把我重要的 key 干掉了咋整, 肯定是把最近最少使用的干掉)
4)volatile-lru: 当内存不足以容纳新写入数据时, 在设置了过期时间的键空间中, 移除最近最少使用的 key.
(这个一般不太合适)
5)volatile-random: 当内存不足以容纳新写入数据时, 在设置了过期时间的键空间中, 随机移除某个 key.
6)volatile-ttl: 当内存不足以容纳新写入数据时, 在设置了过期时间的键空间中, 有更早过期时间的 key 优先移除.
例如: Redis 里有 10 个 key, 现在内存已经满了, 设置的淘汰策略是 allkeys-lru, 此时 Redis 需要删除掉一些 key 来保证你可以继续写入. 在这 10 个 key 中, 其中 1 个 key, 最近 1 分钟被查询了 100 次, 1 个 key, 最近 10 分钟被查询了 50 次, 1 个 key, 最近 1 个小时被查询了 1 次. 肯定那些最近最少使用的被干掉了.
为啥存 Redis 的数据有时候会丢失?
很简单, 你写的数据太多了, 内存占满了, 或者触发了什么条件, 如 Redis 使用了 allkeys-lru 内存淘汰策略, 自动给你清理掉了一些最近很少使用的数据.
4, 结语
主要整理了 Redis 是怎么删除过期 key 的(定期删除 + 惰性删除), 以及 Redis 内存满的时候怎么保证后续写入操作正常进行(内存淘汰策略).
希望对你有帮助. 奥利给!!
(关注左上角公众号, 第一时间阅读文章)
来源: https://www.cnblogs.com/ibigboy/p/12118636.html