一般来说,缓存的容量是小于数据总量的,所以,当缓存数据越来越多,Redis 不可避免的会被写满,这时候就涉及到 Redis 的内存淘汰机制了。我们需要选定某种策略将“不重要”的数据从 Redis 中清除,为新的数据腾出空间。

配置 Redis 内存大小

我们应该为 Redis 设置多大的内存容量呢?

根据“八二原理“,即 80% 的请求访问了 20% 的数据,因此如果按照这个原理来配置,将 Redis 内存大小设置为数据总量的 20%,就有可能拦截到 80% 的请求。当然,只是有可能,对于不同的业务场景需要进行不同的配置,一般建议把缓存容量设置为总数据量的 15% 到 30%,兼顾访问性能和内存空间开销

配置方式(以 5GB 为例,如果不带单位则默认单位是字节):

  • 命令行

    config set maxmemory 5gb
  • 配置文件

  • 查看 maxmemory 命令

    config get maxmemory

Redis 的内存淘汰策略

在 Redis 4.0 版本之前有 6 种策略,4.0 增加了 2种,主要新增了 LFU 算法。

下图为 Redis 6.2.0 版本的配置文件:

其中,默认的淘汰策略是 noevition,也就是不淘汰

我们可以对 8 种淘汰策略可以分为两大类:

  • 不进行淘汰的策略

    • noevition,此策略不会对缓存的数据进行淘汰,当内存不够了就会报错,因此,如果真实数据集大小大于缓存容量,就不要使用此策略了。

  • 会进行淘汰的策略

    • 在设置了过期时间的数据中筛选

      • volatile-random:随机删除
      • volatile-ttl:根据过期时间先后进行删除,越早过期的越先被删除
      • volatile-lru:使用 LRU 算法进行筛选删除
      • volatile-lfu:使用 LFU 算法进行筛选删除
    • 在所有数据中筛选
      • allkeys-random:随机删除
      • allkeys-lru:使用 LRU 算法进行筛选删除
      • allkeys-lfu:使用 LFU 算法进行筛选删除

以 volatile 开头的策略只针对设置了过期时间的数据,即使缓存没有被写满,如果数据过期也会被删除。

以 allkeys 开头的策略是针对所有数据的,如果数据被选中了,即使过期时间没到,也会被删除。当然,如果它的过期时间到了但未被策略选中,同样会被删除。

那么我们如何配置过期策略呢?

  • 命令行

    config set maxmemory-policy allkeys-lru
  • 配置文件

LRU 算法

首先简单介绍一下 LRU 算法:

LRU 全称是 Least Recently Used,即最近最少使用,会将最不常用的数据筛选出来,保留最近频繁使用的数据。

LRU 会把所有数据组成一个链表,链表头部称为 MRU,代表最近最常使用的数据;尾部称为 LRU代表最近最不常使用的数据;

下图是一个简单的例子:

但是,如果直接在 Redis 中使用 LRU 算法也会有一些问题:

LRU 算法在实现过程中使用链表管理所有缓存的数据,这会给 Redis 带来额外的开销,而且,当有数据访问时就会有链表移动操作,进而降低 Redis 的性能。

于是,Redis 对 LRU 的实现进行了一些改变:

  • 记录每个 key 最近一次被访问的时间戳(由键值对数据结构 RedisObject 中的 lru 字段记录)
  • 在第一次淘汰数据时,会先随机选择 N 个数据作为一个候选集合,然后淘汰 lru 值最小的。(N 可以通过 config set maxmemory-samples 100 命令来配置)
  • 后续再淘汰数据时,会挑选数据进入候选集合,进入集合的条件是:它的 lru 小于候选集合中最小的 lru。
  • 如果候选集合中数据个数达到了 maxmemory-samples,Redis 就会将 lru 值小的数据淘汰出去。

LFU 算法

LFU 全称 Least Frequently Used,即最不经常使用策略,它是基于数据访问次数来淘汰数据的,在 Redis 4.0 时添加进来。它在 LRU 策略基础上,为每个数据增加了一个计数器,来统计这个数据的访问次数。

前面说到,LRU 使用了 RedisObject 中的 lru 字段记录时间戳,lru 是 24bit 的,LFU 将 lru 拆分为两部分:

  • ldt 值:lru 字段的前 16bit,表示数据的访问时间戳
  • counter 值:lru 字段的后 8bit,表示数据的访问次数

使用 LFU 策略淘汰缓存时,会把访问次数最低的数据淘汰,如果访问次数相同,再根据访问的时间,将访问时间戳最小的淘汰。

为什么 Redis 有了 LRU 还需要 LFU 呢?

在一些场景下,有些数据被访问的次数非常少,甚至只会被访问一次。当这些数据服务完访问请求后,如果还继续留存在缓存中的话,就只会白白占用缓存空间。

由于 LRU 是基于访问时间的,如果系统对大量数据进行单次查询,这些数据的 lru 值就很大,使用 LFU 算法就不容易被淘汰。

参考

Redis 内存淘汰机制详解的更多相关文章

  1. Redis内存淘汰机制

    转自:https://my.oschina.net/andylucc/blog/741965 摘要 Redis是一款优秀的.开源的内存数据库,我在阅读Redis源码实现的过程中,时时刻刻能感受到Red ...

  2. Redis 内存淘汰机制

    Redis内存淘汰指的是用户存储的一些键被可以被Redis主动地从实例中删除,从而产生读miss的情况,那么Redis为什么要有这种功能?这就是我们需要探究的设计初衷.Redis最常见的两种应用场景为 ...

  3. ARC内存管理机制详解

    ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...

  4. object-c(oc)内存管理机制详解

    1.内存的创建和释放 让我们以Object-c世界中最最简单的申请内存方式展开,谈谈关于一个对象的生命周期.首先创建一个对象: 1 2 3 //“ClassName”是任何你想写的类名,比如NSStr ...

  5. redis 事务 事务机制详解 MULTI、EXEC、DISCARD、WATCH

    1. Redis服务端是个单线程的架构,不同的Client虽然看似可以同时保持连接,但发出去的命令是序列化执行的,这在通常的数据库理论下是最高级别的隔离2. 用MULTI/EXEC 来把多个命令组装成 ...

  6. Java的内存回收机制详解X

    http://blog.csdn.net/yqlakers/article/details/70138786 1 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前 ...

  7. go - 内存分配机制详解

    一般程序的内存分配,从高位到低位依次为 全局静态区:用于存储全局变量.静态变量等:这部分内存在程序编译时已经分配好,由操作系统管理,速度快,不易出错. 栈:函数中的基础类型的局部变量:由程序进行系统调 ...

  8. Redis 中的过期删除策略和内存淘汰机制

    Redis 中 key 的过期删除策略 前言 Redis 中 key 的过期删除策略 1.定时删除 2.惰性删除 3.定期删除 Redis 中过期删除策略 从库是否会脏读主库创建的过期键 内存淘汰机制 ...

  9. redis 的过期策略都有哪些?内存淘汰机制都有哪些?

    面试题 redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现? 面试官心理分析 如果你连这个问题都不知道,上来就懵了,回答不出来,那线上你写代码的时候,想当然的认为写进 r ...

随机推荐

  1. 记angular和asp.net使用grpc进行通信

    AspNetCore配置grpc服务端 新建一个Demo项目: GrpcStartup, 目录结构如下图: GrpcStartup.GrpcServices需要安装下面的依赖 <PackageR ...

  2. BZOJ4668: 冷战 (并查集 + LCA)

    题意:动态给点连边 询问两个点之间最早是在第几个操作连起来的 题解:因为并查集按秩合并 秩最高是logn的 所以我们可以考虑把秩看作深度 跑LCA #include <bits/stdc++.h ...

  3. 洛谷P1119-灾后重建-floyd算法

    洛谷P1119-灾后重建 题目描述 给出\(B\)地区的村庄数NN,村庄编号从\(0\)到\(N-1\),和所有\(M\)条公路的长度,公路是双向的. 给出第\(i\)个村庄重建完成的时间\(t_i\ ...

  4. VS制作可自动覆盖旧版本的安装包

    1.设置属性 DetectNewerInstalledVersion=TrueInstallAllUsers = TrueRemovePreviousVersion = True 2.增加软件版本号, ...

  5. System.Windows.Forms.Help

    在开发过程中,基本都需要实现帮助功能,而一般帮助功能就是打开一个帮助文档,System.Windows.Forms提供了Help类用于打开帮助文档,挺方便的. Help类提供的方法如下:   Name ...

  6. codeforces 1000C - Covered Points Count 【差分】

    题目:戳这里 题意:给出n个线段,问被1~n个线段覆盖的点分别有多少. 解题思路: 这题很容易想到排序后维护每个端点被覆盖的线段数,关键是端点值不好处理.比较好的做法是用差分的思想,把闭区间的线段改为 ...

  7. 鸟哥的linux私房菜——第七章学习(Linux 磁盘与文件系统管理)

    1.1).文件系统特征 我们称呼一个可被挂载的数据为一个文件系统而不是一个分区! 文件系统通常会将这两部份的数据分别存放在不同的区块,权限与属性放置到 inode 中,至于实际数据则放置到 data ...

  8. Redis五大类型及底层实现原理

    目录 简单动态字符串链表字典跳跃表整数集合压缩列表对象 对象的类型与编码字符串对象列表对象哈希对象 集合对象有序集合对象类型检查与命令多态内存回收对象共享对象的空转时长 简单动态字符串  导读 Red ...

  9. Dapr 正式发布1.0

    年前我写了一篇博客<Dapr 已在塔架就位 将发射新一代微服务>, 今天Dapr 正式发布了1.0 : Dapr Runtime v1.0.0 Dapr dotnet SDK v1.0.0 ...

  10. Bazinga means

    Bazinga means Bazinga https://www.dictionary.com/e/slang/bazinga/ refs xgqfrms 2012-2020 www.cnblogs ...