Redis问题总结

什么是Redis

Redis 是一种基于内存的数据库,对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景。
Redis 提供了多种数据类型来支持不同的业务场景,比如 String(字符串)、Hash(哈希)、 List (列表)、Set(集合)、Zset(有序集合)、Bitmaps(位图)、HyperLogLog(基数统计)、GEO(地理信息)、Stream(流),并且对数据类型的操作都是原子性的,因为执行命令由单线程负责的,不存在并发竞争的问题。
除此之外,Redis 还支持事务 、持久化、Lua 脚本、多种集群方案(主从复制模式、哨兵模式、切片机群模式)、发布/订阅模式,内存淘汰机制、过期删除机制等等

数据类型以及使用场景分别是什么?

String(SDS(简单动态字符串)实现) :可以是字符串,也可以是整数浮点,可以做基本的操作,也可以对整数浮点做加减操作
List(3.2之前使用双向链表或压缩列表,之后quicklist):双向列表,对链表的两对push和pop操作,
hash(压缩列表或哈希表,Redis 7.0 中,压缩列表数据结构已经废弃了,交由 listpack):包含键值对的无序散列值。
Set(哈希表或整数集合):无序集合。结构是字符串集合,包含基本的删查等操作,还可以做一些并集、交集、差集等操作
Zset(压缩列表或跳表,7.0 中,压缩列表数据结构已经废弃了,交由 listpack 数据结构来实现了):包含字符串和分数。排序按照分数来,包含基本的方法,还有根据分值范围获取元素。

Redis单线程为什么那么快
  1. 大部分操作是在内存中完成,采用了高效的数据结构,因此redis的瓶颈可能是机器的内存或者网络带宽,所以采用单线程(命令)解决方案
  2. redis单线程模型可以避免线程之间的竞争,省去线程切换带来的消耗,而且也不会导致死锁
  3. redis采用了I/O多路复用的机制处理大量的客户端请求。采用epoll机制 。(几个关键词,从初始化开始讲
    clients_pending_read 、
    clients_pending_write
    beforeSleep-》handleClientsWithPendingReadsUsingThreads;
    取模
    io_threads_num的方式
    io_threads_list[target_id] )
Redis 6.0 之前为什么使用单线程?

来自官网的FAQ。
CPU 并不是制约 Redis 性能表现的瓶颈所在,更多情况下是受到内存大小和网络I/O的限制,所以 Redis 核心网络模型使用单线程并没有什么问题,如果你想要使用服务的多核CPU,可以在一台服务器上启动多个节点或者采用分片集群的方式
除了上面的原因:我觉着多线程增加了系统复杂度,可能存在线程切换,甚至死锁等问题

Redis 6.0 之后为什么引入了多线程?

在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上
对于网络IO采用多线程来处理,但是命令的处理还是单线程。官方表示,多线程IO特性对性能至少提升一倍以上。在redis.conf 配置一下
在redis6.0之后,redis启动的时候,开启多线程 默认创建额外的6个线程(不包含主线程)

  • Redis-server : Redis的主线程,主要负责执行命令;
  • bio_close_file、bio_aof_fsync、bio_lazy_free:三个后台线程,分别异步处理关闭文件任务、AOF刷盘任务、释放内存任务;
  • io_thd_1、io_thd_2、io_thd_3:三个 I/O 线程,io-threads 默认是 4 ,所以会启动 3(4-1)个 I/O 多线程,用来分担 Redis 网络 I/O 的压力。
Redis持久化
Redis如何实现数据不丢失?

为了保证数据不丢失,redis实现了数据持久化的机制,这个机制会把数据存储到磁盘,这样在redis重启就能够从磁盘中恢复原有的数据。
redis有三种数据持久化的方式:

  1. AOF日志,每执行一条写操作命令,就把该命令以追加的方式写入到一个文件中
  2. RDB快照:将某一时刻的内存数据,以二进制的方式写入磁盘
  3. 混合持久化:集成了AOF和RDB的优点
AOF日志如何实现?

redis写入aof日志的过程:
执行写操作命令完成-》命令追加到server.aof_buf缓冲区-》I/O系统调用write(),用户态和内核态切换-》内核缓冲区page cache -》由内核发起读操作-》磁盘
具体说说:

  1. redis执行完写操作命令后,会将命令追加到server.aof_buf缓冲区
  2. 通过write()系统调用,将aof_buf缓冲区的数据写入到AOF文件中,此时数据还没有写进硬盘,此时数据还没有到硬盘,而是拷贝到了内核缓冲区page cache中,等待内核将数据写入硬盘
    appendfsyn配置项可以有以下3种策略
    • always,每次写完,同步将aof日志数据写回硬盘( 令写入aof_buf后调用系统fsync操作同步到AOF文件
    • everysec:每秒,每次写完操作命令之后,先将命令写到AOF文件的内核缓冲区,然后每隔一秒将缓冲区中的内容写回到硬盘(命令写入到aof_buf后调用系统write操作,将数据拷贝到内核缓冲区page cache中,fsync每秒执行一次
    • no:: 不由redis控制写入磁盘的时间,转交给操作系统控制,也就是每次写完操作命令后,将命令写到内核缓冲区,由系统决定什么时候回写(page cache 满,通常周期最迟30秒

AOF 日志过大,会触发什么机制:

AOF是一个日志文件,随着执行的写操作命令越来越多,文件的大小会越来越大。如果当AOF日志文件过大就会带来性能问题,比如重启redis,如果文件过大,整个恢复过程会很慢。
所以为了避免aof文件越来越大,提供了AOF重写机制,当AOF文件的大小超过所设定的阀值后,redis就会触发aof重启机制,来压缩文件。
如何实现:读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到新的aof文件,等全部记录完后,将新的aof文件替换掉现在的aof文件。读取的是name最新的value值,老的value就没用了

AOF重

重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的,两个好处:

  1. 子进程进行aof重写期间,主进程可以继续处理命令请求,避免阻塞主进程
  2. 子进程带有主进程的数据副本,这里使用进程而不是线程的原因是,如果使用线程,多线程之间回共享内存,修改共享数据的时候,需要用锁来保证安全,降低性能。而使用子进程,创建子进程的时候,父子进程是共享内存数据的,不过这个共享内存只能以只读的方式,而当父子进程任意一方修改共享数据,就会发生写时复制,于是父子进程就有了独立数据副本,不用加锁来保证数据安全

过程
触发重写机制后,主进程就会创建重写 AOF 的子进程,此时父子进程共享物理内存,重写子进程只会对这个内存进行只读,重写 AOF 子进程会读取数据库里的所有数据,并逐一把内存数据的键值对转换成一条命令,再将命令记录到重写日志(新的 AOF 文件)。

但是重写过程中,主进程依然可以正常处理命令,那问题来了,重写 AOF 日志过程中,如果主进程修改了已经存在 key-value,那么会发生写时复制,此时这个 key-value 数据在子进程的内存数据就跟主进程的内存数据不一致了,这时要怎么办呢?

为了解决这种数据不一致问题,Redis 设置了一个 AOF 重写缓冲区,这个缓冲区在创建 bgrewriteaof 子进程之后开始使用。在重写 AOF 期间,当 Redis 执行完一个写命令之后,它会同时将这个写命令写入到 「AOF 缓冲区-保证现有的aof文件正常-万一重写出现问题,原有的还是正常的」和 「AOF 重写缓冲区-记录了从重写开始以来的所有数据」。复制完成后,给主进程发送一个信号,然后主进程会将AOF重写缓冲区的所有内容追加到新的AOF文件中

RDB 快照是如何实现的呢?

因为AOF日志记录的是操作命令,不是实际的数据,所以用AOF文件恢复时,需要执行全量的日志,一旦AOF日志非常多,恢复就比较慢。

为了解决这个问题,Redis增加了RDB快照,所谓快照就是记录一瞬间的东西。RDB快照就是记录某一瞬间的内存数据,记录的是实际数据。因此做数据恢复的时候,RDB恢复数据比AOF效率高。

RDB做快照回阻塞线程嘛?

Redis提供了两个命令来生成RDB文件,分别是save和bgsave,他们的区别就自安于是否在主线程执行。

  • 执行save命令,会在主线程生成RDB文件,和执行命令的在同一线程,如果写入RDB时间长,会阻塞主线程
  • 执行bgsave命令,会创建一个子进程来生成RDB,这样可以避免主线程的阻塞
    提供了如下配置(多少秒满足多少次修改才会触发)
# 900秒内,数据至少进行一次修改
save 900 1
# 300秒,对数据库进行了至少10次修改
save 300 10
# ...
save 60 10000

Redis的快照是全量快照,也就是每次执行快照,都是把内存中所有的数据都记录到磁盘。所以快照是一个比价重的操作,太频繁,性能影响大。频率太低,服务器故障时候,丢的数据多。

RDB 在执行快照的时候,数据能修改吗?

可以的,在执行bgsave过程中,redis依然可以继续处理操作命令,也就是说数据是可以被修改的,关键技术在于写时复制(Copy-On-Write,COW)

执行bgsave命令的时候,会通过fork创建子进程,此时子进程和父进程是共享同一片内存数据的,因为创建子进程的时候,会复制父进程的页表,但是页表执行的物理内存还是同一个,如果主线程执行写操作,则被修改的数据会复制一份副本,然后 bgsave 子进程会把该副本数据写入 RDB 文件,在这个过程中,主线程仍然可以直接修改原来的数据

为什么会有混合持久化?

RDB优点是数据恢复速度快,但是快照的频率不好把握。频率低,丢失的数据就比较多,频率高,影响性能。
AOF优点是丢失的数据少,但是数据恢复慢。
Redis4.0提出了混合使用AOF日志和内存快照,也叫混合持久化,既保证了Redis重启的速度,也降低了数据丢失风险。

混合持久化的工作是在AOF日志重写过程中,当开启混合持久化时,在AOF重启日志时,fork出来的子进程会将与主进程共享的内存数据以RDB方式写入到AOF文件中,然后主进程处理操作的命令会被记录到重写缓冲区,重写缓冲区中增量命令会以AOF方式写入到AOF文件,写入完成后通知主进程将新的含有RDB格式和AOF格式的AOF文件替换旧的AOF文件。
混合持久化AOF文件:前半部分是RDB格式的全量数据,后半部分是AOF格式的增量数据
优点:兼顾了AOF和RDB的优点
缺点:AOF文件中的RDB部分,可读性很差

Redis 集群
Redis如何实现服务高可用

设计一个高可用的服务员,一定是从服务的节点来考虑的。如主从复制、哨兵模式、集群。

主从复制

主从复制是Redis高可用最基础的保证,实现方案将之前的一台Redis服务器,同步数据到多台从Redis服务器上,即一主多从的模式,且主从服务器之间采用的是读写分离的方式。

主服务器可以进行读写操作,当发生写操作时自动将写操作同步给从服务器,而从服务器一般是只读,并接受主服务器同步过来写操作命令,然后执行这条命令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NQBscmZl-1678240020333)(en-resource://database/2295:0)]
也就是说,所有的数据修改都是在主服务器上进行,然后将最新的数据同步非从服务器(异步),这样使得主从服务器的数据是一致的。

通过replicaof命令确定是谁的从服务器。
第一次同步

  • 第一阶段是建立链接、协商同步(runId和offset。从服务器发送psync命令标识想同步数据了,主发送fullresync表示全量复制);
  • 第二阶段是主服务器同步数据给从服务器(bgsave,replication buffer);
  • 第三阶段是主服务器发送新写操作命令给从服务器(将缓冲区的数据发给从服务器)
    第一次同步之后,双方会维持一个TCP连接(基于长连接的命令传播),主服务的后续操作通过这个连接给从服务器
增量复制

如果tcp长连接断了,无法命令传播了,再连上网,如何处理:

  1. 发送psync 命令给主服务器,此时psyc命令里面的offset参数不是-1;
  2. 主服务器收到后,用continue 响应命令告诉从服务器接下来采用增量复制的方式同步数据
  3. 主服务将失联这段期间的写命令发给从服务器
    (也将命令写到了环形缓冲区;主服务器使用 master_repl_offset 来记录自己「写」到的位置,从服务器使用 slave_repl_offset 来记录自己「读」到的位置);如何不在范围内了,全量复制
哨兵模式

主从有个问题,宕机的时候,需要手动进行恢复。
所以有了哨兵模式,因为哨兵模式做到了可以监控主从服务器,并且提供了主从节点的故障转移
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCpzDpQX-1678240020335)(en-resource://database/2297:0)]
哨兵就负责三件事:
监控、选主、通知
如何判断主节点真的故障了?
哨兵每隔1秒会给所有的主从节点发送ping命令,当主从节点收到ping命令后,会发送一个相应命令给哨兵,这样判断是否运行正常。
主观下线和客观下线(哨兵集群)
,任何一个「候选者」,要满足两个条件成为Leader:

  • 第一,拿到半数以上的赞成票;
  • 第二,拿到的票数同时还需要大于等于哨兵配置文件中的 quorum 值。
主从故障转移的过程是怎样的?
  1. 在已下线主节点(旧主节点)属下的所有「从节点」里面,挑选出一个从节点,并将其转换为主节点。(从网络、优先级、复制进度、ID 号四个方面比较)
  2. 让已下线主节点属下的所有「从节点」修改复制目标,修改为复制「新主节点」
  3. 将新主节点的 IP 地址和信息,通过「发布者/订阅者机制」通知给客户端
  4. 继续监视旧主节点,当这个旧主节点重新上线时,将它设置为新主节点的从节点;#步骤一:选出新主节点。

哨兵集群通过发布订阅的方式来相互发现的。主节点上有一个名为 sentinel:hello 的频道,
不同哨兵就是通过它来相互发现,实现互相通信的。

切片集群模式

当redis缓存数据量大到一台服务器无法缓存的时候,就需要使用redis切片集群方案(一致性hash),将数据分部到不同的服务器上,降低对单点的依赖,提高服务的读写性能。
redis cluster方案采用哈希槽(hash solt),来处理数据和节点之间的映射关系。一个切片集群共有16384个哈希槽,根据key找到对应的hash槽。分为下面两步:

  1. 根据key,使用CRC16算法计算一个16bit
    的值
  2. 再用16bit值对16384取模,得到0-16383范围内的模数,模数代表一个相应的哈希槽。
集群脑裂导致数据丢失怎么办?

什么是脑裂?
现象:好比一个人有两个大脑,不知道受谁控制
即:由于网络问题,集群之间失去联系。主从数据不同步,重新选举,产生了两个主服务。等网络恢复,旧节点降级为从节点,再与主节点(新选举出来的)同步的时候,回清空从节点(老的主节点)的数据,导致之前客户端的数据丢失
解决方案

当主节点发现从节点下线,或者通信超时的总数小于阀值时,禁止主节点写入数据,直接把错误返回给客户端

  • min-slaves-to-write x,主节点必须要有至少 x 个从节点连接,如果小于这个数,主节点会禁止写数据。

  • min-slaves-max-lag x,主从数据复制和同步的延迟不能超过 x 秒,如果超过,主节点会禁止写数据。
    满足上面两条才可以往主库写入数据。

    解决问题的出发点是:某些时刻不能接收数据

Redis过期删除与内存淘汰

redis是可以对key设置过期时间的,因此需要有响应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略。

每当我们对一个key设置了过期时间时,redis会把该key戴上过期时间存储到一个过期字典,也就是说过期字典保存了数据库中所有的key的过期时间。

当我们查询一个key时,redis首先检查该key是否存在于过期字典中:

  • 如果不在正常读取该值
  • 如果存,获取key的过期时间,然后与当前系统时间进行对比,如果比系统时间大,那就没有过期,否则判定该key已经过期

Redis使用的过期策略是惰性删除+定期删除这两种策略配置使用

什么是惰性删除策略?

惰性删除策略的做法是:不主动删除过期键,每次从数据库访问key时,都会检测key是否过期,如果过期则删除该key(返回null给客户端)。

惰性删除策略的优点

  • 每次访问的时候,才会检查key是否过期,所以此策略只会使用很少的系统资源,对cpu友好

惰性删除策略的缺点

  • 如果一个 key 已经过期,而这个 key 又仍然保留在数据库中,那么只要这个过期 key 一直没有被访问,它所占用的内存就不会释放,造成了一定的内存空间浪费。对内存不友好

什么是定期删除策略?

定期删除策略做法是:每隔一段时间(随机)从数据库中取出一定数据的key进行检查,并删除其中过期的key

Redis的定期删除流程:

  1. 从过期字典中随机取出20个key;
  2. 检查这20个key是否过期,并删除已过期的key
  3. 如果本轮过期的key超过5个(20/4),即过期key/抽查总数比例大约25%,重复步骤1;如果小于25%,则停止删除过期key,等待下一轮再检查

可以看出定期删除是一个循环过程,那redis为了保证定期删除不会出现循环过度,导致线程卡死现象,增加了一个时间上限-25ms

定期删除策略的优点

  • 通过限制删除操作的执行时长和频率,来减少删除操作对cpu的影响,同事也能删除一部分过期的数据减少过期key对空间的无效占用。

定期删除的缺点

  • 难以确定删除操作执行的时长和频率,如果太频繁,对cpu不友好,如果执行太少,又和惰性删除一样了,过期的key占用内存无法及时释放。

可以看到,惰性删除策略和定期删除策略都有各自的优点,所以 Redis 选择「惰性删除+定期删除」这两种策略配和使用,以求在合理使用 CPU 时间和避免内存浪费之间取得平衡。

conf配置的是,每秒进行10次检查(使用定期检查策略);每次检查20个数据

Redis持久化时,对过期的key会如何处理?

两种格式:RDB(Redis Database)和AOF(Append Only File),分别来看。

RDB文件分为两个阶段,RDB文件生成阶段和加载阶段

  • RDB文件生成阶段:从内存状态持久化成RDB文件的时候,会对key进行过期检查,过期的key不会保存到新的RDB文件中
  • RDB加载阶段:要看服务器是主服务器还是从服务器,分别对应两种情况:
    • 如果是主服务器运行模式:会对key进行检查,过期的key不会载入到数据库中
    • 如果是从服务器运行模式:载入RDB文件的时候,不论键是否过期都会被载入到数据库中。但是由于主动服务器数据同步的时候,从服务器数据会被清空,所以也没影响。

AOF文件分为两个阶段(因为是命令的形式,加载的时候直接执行命令,我猜加载不会判断key),AOF文件写入阶段和AOF重写阶段

  • AOF 文件写入阶段:当 Redis 以 AOF 模式持久化时,如果数据库某个过期键还没被删除,那么 AOF 文件会保留此过期键,当此过期键被删除后,Redis 会向 AOF 文件追加一条 DEL 命令来显式地删除该键值
  • AOF 重写阶段:执行 AOF 重写时,会对 Redis 中的键值对进行检查,已过期的键不会被保存到重写后的 AOF 文件中,因此不会对 AOF 重写造成任何影响。
Redis 主从模式,对过期key如何处理?

Redis运行在主从模式下,从库不会进行过期扫描,从库对过期key的处理是被动的。也就是说,即使从库中的key过期了,如果有客户端访问从库时,依然可以得到key值,像未过期的key一样返回(3.2以上优化了,会返回null;从节点使用其独有的逻辑时钟来标注一个键不存在)。

从库的过期key键处理依靠主服务器控制,主库再key到期的时候,会在aof文件中追加一条del指令,同步所有的从库,从库根据这条del指令来删除过期的key。

Redis内存满了,会发生什么?

在redis的运行内尺寸达到某个阀值,就会触发内存淘汰机制,这个阀值就是我们设置的最大运行内存-maxmemory.

Redis 内存淘汰策略有哪些?

redis内存淘汰策略共8种,这8种大体可分为“不进行数据淘汰”和“进行数据淘汰”两类策略。

  1. 不进行数据淘汰的策略
    • noeviction(redis3.0之后,默认的内存淘汰策略):当运行内存超过设置的最大内存时,不淘汰任何数据,而是停止服务,直接返回错误。
  2. 进行数据淘汰的策略。可以细分为在设置了过期时间的数据中进行淘汰所有数据范围内进行淘汰
    • 设置了过期时间的数据中进行淘汰
      1. volatile-random:随机淘汰设置了过期时间的任意键值
      2. volatile-ttl:优先淘汰更早过期的键值
      3. volatile-lru:3.0之前默认策略,淘汰所有设置过期时间键值中,最久未使用
      4. volatile-lfu:4.0新增策略,淘汰所有设置了过期时间的键值中,最少使用的键值。
    • 在所有数据范围内进行淘汰
      1. alkeys-random:随机淘汰任意键值
      2. allkeys-lru:淘汰整个键值中最久未使用的键值
      3. alkeys-lfu:淘汰使用最少的键值
LRU 算法和 LFU 算法有什么区别?

什么是LRU算法?

LRU全称是 Least Recently Used ,最近最少使用,会选择淘汰最近最少使用的数据。

传统LRU算法的实现是基于“链表”结构,链表中的元素按照操作顺序从前往后排列,最新操作的键会被移动到表头,当需要淘汰的时候,只需要删除链表尾部的原生即可。

Redis并没有使用这样方式实现的LRU算法,因为传统LRU算法有两个问题:

  1. 需要用链表管理所有的缓存数据,这会带来额外的空间开销
  2. 当数据被访问时,需要在链表上把该数据移动到表头,如果有大量数据访问,会带来很多链表移动的操作,会很耗时,进而会降低redis缓存性能

Redis是如何实现LRU算法的

Redis实现的是一种近似LRU算法,目的是为了更好的节约内存,它的实现方式是在redis的对象结构体重添加一个额外的字段,用于记录此记录的最后一次访问时间

当Redis进行内存淘汰时,会使用随机的方式来淘汰数据,它是随机取 5 个值(此值可配置),然后淘汰最久没有使用的那个

3.0优化

  • 优化后算法会维护一个候选池,大小为 16,池中的数据根据访问时间进行排序,第一次采样选取的 key 都会放入池中。
    • 随后每次随机选取的 key 只有在访问时间小于池中最小的时间才会放入池中,直到候选池被放满。
    • 池放满后,如果有新的 key 需要放入,则将池中最近被访问的移出池。
    • 需要淘汰数据的时候,直接从池中选取最久没被访问的 key 淘汰掉。

Redis实现的LRU算法的优点:

  1. 不需要维护一个大链表,省空间
  2. 不用每次访问时移动链表项目,提高性能

但是LRU有一个问题,无法解决缓存污染问题(它无法正确的表示一个Key的热度,如果一个key从未被访问过,仅仅发生内存淘汰的前一会儿被用户访问了一下,在LRU算法中这会被认为是一个热key),比如应用一次读取了大量的数据,而这些数据只会被读取这一次,那么这些数据会留存在 Redis 缓存中很长一段时间,造成缓存污染。

因此,Redis4.0之后引入了LFU算法来解决这个问题。

什么是LFU算法?

Least Frequently Used ,最不经常使用。核心思想是:“如果数据过去被访问多次,那么将来访问的频率也会更高”

LFU 算法会记录每个数据的访问次数。当一个数据被再次访问时,就会增加该数据的访问次数。这样就解决了偶尔被访问一次之后,数据留存在缓存中很长一段时间的问题

Redis 是如何实现 LFU 算法的?

LFU算法相对于LRU算法的实现,多记录了访问频次的信息。Redis对象结构如下:

typedef struct redisObject {
	unsigned type:4;		// 4 bits 对象的类型(zset、set、hash等)
    unsigned encoding:4;	// 4 bits 对象的存储方式(ziplist、intset等)
    unsigned lru:24;		// 24bits 记录对象的访问信息
    int refcount;			// 4 bytes 引用计数
    void *ptr;				// 8 bytes (64位操作系统),指向对象具体的存储地址/对象body
}robj;

Redis 对象头中的 lru 字段,在 LRU 算法下和 LFU 算法下使用方式并不相同。

  • 在LRU算法中:redis对象头的24bits的lru字段是用来记录key的访问时间戳,用来比较时间进行淘汰。
  • 在LFU算法中,Redis对象头的 24 bits 的 lru 字段被分成两段来存储,高 16bit 存储 ldt(Last Decrement Time),用来记录 key 的访问时间戳;低 8bit 存储 logc(Logistic Counter),用来记录 key 的访问频次

LFU 维护了一个与 LRU 相同的候选池,用于节省排序所有 key 访问频率所需要的时间。一种根据时间降低 key 访问频率的机制

Redis LFU 淘汰策略逻辑:

  • 随机抽样选出N个数据放入【待淘汰数据池 evictionPoolEntry】;
  • 再次淘汰:随机抽样选出【最多N个数据】,更新 Ldt 和 counter 的值,只要 counter 比【待淘汰数据池 evictionPoolEntry】中的【任意一条】数据的 counter 小,则将该数据填充至 【待淘汰数据池】;
    • evictionPoolEntry 的容容量是 EVPOOL_SIZE = 16;
  • 执行淘汰: 挑选【待淘汰数据池】中 counter 最小的一条数据进行淘汰;

后台线程
6.0模型

https://wnanbei.github.io/post/redis-%E7%BC%93%E5%AD%98%E4%B8%8E%E6%B7%98%E6%B1%B0%E7%AD%96%E7%95%A5/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值