💎 Redis 面试题集合
本文档涵盖了 Redis 核心知识点,包括持久化机制、过期策略、内存淘汰、缓存问题、哨兵机制、分布式锁等面试高频考点。
📑 目录
1. Redis 持久化机制(RDB 与 AOF)
1.1 为什么需要持久化?
Redis 之所以能够提供高速读写操作是因为数据存储在内存中,但这也带来了一个风险:在服务器宕机或断电的情况下,内存中的数据会丢失。为了解决这个问题,Redis 提供了持久化机制来确保数据的持久性和可靠性。
1.2 Redis 持久化机制概览
| 持久化方式 | 说明 |
|---|---|
| RDB (Redis Data Base) | 内存快照,全量备份 |
| AOF (Append Only File) | 增量日志,记录写命令 |
| 混合持久化 | RDB + AOF 结合 |
1.3 RDB 持久化
1.3.1 什么是 RDB?
在指定的时间间隔内将内存中的数据集快照写入磁盘。RDB 是内存快照(内存数据的二进制序列化形式)的方式持久化,每次都是从 Redis 中生成一个快照进行数据的全量备份。
1.3.2 RDB 持久化流程
┌─────────────┐
│ 主进程 │
│ 继续处理 │
│ 客户端请求 │
└──────┬──────┘
│ 1. Fork 子进程
▼
┌─────────────┐ ┌─────────────┐
│ 子进程 │────▶│ 共享内存 │
│ 备份数据 │ │ (COW机制) │
└──────┬──────┘ └─────────────┘
│
│ 2. 将共享内存数据
│ 写到临时 RDB 文件
▼
┌─────────────┐
│ 临时 RDB 文件 │
└──────┬──────┘
│ 3. 完成写入,
│ 替换旧 RDB 文件
▼
┌─────────────┐
│ dump.rdb │
└─────────────┘RDB 持久化方案进行备份时,Redis 会单独 fork 一个子进程来进行持久化,会将数据写入一个临时文件中,持久化完成后替换旧的 RDB 文件。
在整个持久化过程中,主进程(为客户端提供服务的进程)不参与 IO 操作,这样能确保 Redis 服务的高性能。RDB 持久化机制适合对数据完整性要求不高但追求高效恢复的使用场景。
1.3.3 RDB 触发规则
手动触发
| 命令 | 说明 | 特点 |
|---|---|---|
SAVE | 阻塞当前 Redis 进程,直到 RDB 持久化过程完成 | 如果内存实例较大会造成长时间阻塞,不建议使用 |
BGSAVE | Redis 主进程 fork 创建子进程,由子进程完成持久化 | 阻塞时间很短(微秒级),推荐使用 |
自动触发 - 配置触发
在 Redis 安装目录下的 redis.conf 配置文件中搜索 /snapshot 即可快速定位:
# 默认配置(注释状态)
# save 3600 1 # 3600 秒内有 1 个 key 被修改,触发 RDB
# save 300 100 # 300 秒内有 100 个 key 被修改,触发 RDB
# save 60 10000 # 60 秒内有 10000 个 key 被修改,触发 RDB自动触发 - shutdown 触发
在客户端执行 SHUTDOWN 命令时会触发 RDB 持久化:
# 删除已存在的 RDB 文件
rm -rf dump.rdb
# 连接 Redis
redis-cli -p 6379
# 执行 shutdown
127.0.0.1:6379> SHUTDOWN
# 退出
not connected> QUIT
# 查看目录,会重新生成 dump.rdb
ll自动触发 - flushall 触发
执行 FLUSHALL 命令会清空 Redis 所有数据库的数据(16 个库数据都会被删除):
# 删除 RDB 文件
rm -rf dump.rdb
# 连接 Redis
redis-cli -p 6379
# 查看数据量
127.0.0.1:6379> DBSIZE
(integer) 7
# 执行 FLUSHALL
127.0.0.1:6379> FLUSHALL
OK
# 退出
127.0.0.1:6379> QUIT
# 查看目录,会生成空的 dump.rdb
ll1.3.4 RDB 优缺点
✅ 优点
- 性能高:RDB 持久化是通过生成一个快照文件来保存数据,因此在恢复数据时速度非常快
- 文件紧凑:RDB 文件是二进制格式的数据库文件,相对于 AOF 文件来说,文件体积较小
❌ 缺点
- 可能丢失数据:由于 RDB 是定期生成的快照文件,如果 Redis 意外宕机,最近一次的修改可能会丢失
💡 提示:Redis 持久化默认开启为 RDB 持久化
1.4 AOF 持久化
1.4.1 什么是 AOF?
AOF 持久化需要手动修改配置文件开启。AOF 持久化方案进行备份时,客户端所有请求的写命令都会被追加到 AOF 缓冲区中,缓冲区中的数据会根据 Redis 配置文件中配置的同步策略来同步到磁盘上的 AOF 文件中。
1.4.2 AOF 持久化流程
客户端写请求 ──▶ Redis 进程 ──▶ AOF 缓冲区 ──▶ AOF 日志文件
│
▼
AOF 日志重写(瘦身)
│
▼
启动时读取 AOF 恢复数据当 AOF 的文件达到重写策略配置的阈值时,Redis 会对 AOF 日志文件进行重写,给 AOF 日志文件瘦身。Redis 服务重启的时候,通过加载 AOF 日志文件来恢复数据。
1.4.3 AOF 配置
AOF 默认不开启,需要修改为 appendonly yes:
# 开启 AOF
appendonly yes
# 关闭 AOF+RDB 混合模式(设为 no)
aof-use-rdb-preamble no1.4.4 AOF 同步策略
# 可选值:always | everysec | no
appendfsync everysec| 策略 | 说明 | 特点 |
|---|---|---|
always | 每次 Redis 写操作都写入 AOF 日志 | 非常耗性能,数据最安全 |
everysec | 每秒刷新一次缓冲区中的数据到 AOF 文件 | 默认策略,兼容性能和数据完整性的折中方案,理论上丢失数据在一秒钟左右 |
no | 交给操作系统判断何时刷新 | 不推荐使用,丢失数据可能性大 |
1.4.5 AOF 修复功能
Redis 7 版本,AOF 文件存储在 appendonlydir 文件夹下:
base:基准文件incr:追加数据
修复步骤:
# 1. 启动 Redis
redis-server conf/redis-config.conf
# 2. 连接 Redis 并写入数据
redis-cli -p 6379
127.0.0.1:6379> SET aa aa
OK
127.0.0.1:6379> SET bb bb
OK
127.0.0.1:6379> SET cc cc
OK
# 3. 如果 AOF 文件损坏,重启会报错
# 使用 redis-check-aof 修复
redis-check-aof --fix appendonlydir/appendonly.aof.1.incr.aof
# 4. 重新启动 Redis
redis-server conf/redis-config.conf
# 5. 验证数据
redis-cli -p 6379
127.0.0.1:6379> KEYS *1.4.6 AOF 重写
重写其实是针对 AOF 存储的重复性冗余指令进行整理,比如有些 key 反复修改,又或者 key 反复修改后最终被删除,这些过程中的指令都是冗余且不需要存储的。
自动重写:
当 AOF 日志文件达到阈值时会触发自动重写。
# 当 AOF 文件体积达到上次重写之后的体积的 100% 时,会触发 AOF 重写
auto-aof-rewrite-percentage 100
# 当 AOF 文件体积超过这个阈值时,会触发 AOF 重写
auto-aof-rewrite-min-size 64mb手动重写:
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started1.4.7 AOF 优缺点
✅ 优点
- 数据更加可靠:AOF 持久化记录了每个写命令的操作,因此在出现故障时,可以通过重新执行 AOF 文件来保证数据的完整性
- 可以保留写命令历史:AOF 文件是一个追加日志文件,可以用于回放过去的写操作
❌ 缺点
- 文件较大:由于记录了每个写命令,AOF 文件体积通常比 RDB 文件要大
- 恢复速度较慢:当 AOF 文件较大时,Redis 重启时需要重新执行整个 AOF 文件,恢复速度相对较慢
1.5 混合持久化
Redis 4.0 版本开始支持混合持久化,因为 RDB 虽然加载快但是存在数据丢失,AOF 数据安全但是加载缓慢。
混合持久化通过以下配置开启(Redis 4.0 以上版本默认开启):
aof-use-rdb-preamble yes开启混合持久化之后,appendonlydir 文件夹下会同时存在一个 RDB 文件与一个 AOF 文件。
1.6 持久化方案总结
| 方案 | 推荐度 | 适用场景 |
|---|---|---|
| RDB + AOF 混合 | ⭐⭐⭐⭐⭐ | 推荐两者均开启 |
| 单独 RDB | ⭐⭐⭐ | 对数据不敏感的场景 |
| 单独 AOF | ⭐⭐ | 不建议单独使用,因为可能会出现 Bug |
| 都不开启 | ⭐ | 纯内存缓存场景 |
2. Redis 过期策略
2.1 惰性删除(Lazy Expiration)
当客户端尝试访问某个键时,Redis 会先检查该键是否设置了过期时间,并判断是否过期。如果键已过期,则 Redis 会立即将其删除。
⚠️ 注意:该策略可以最大化地节省 CPU 资源,却对内存非常不友好。极端情况可能出现大量的过期 key 没有再次被访问,从而不会被清除,占用大量内存。
2.2 定期删除(Active Expiration)
Redis 会每隔一段时间(默认 100 毫秒)随机检查一部分设置了过期时间的键,通过循环遍历方式,逐个检查键是否过期,并删除已过期的键值对。
通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得 CPU 和内存资源达到最优的平衡效果。
2.3 过期策略总结
Redis 中同时使用了惰性过期和定期过期两种过期策略:
- 假设 Redis 当前存放 20 万个 key,并且都设置了过期时间,如果每隔 100ms 就去检查这全部的 key,CPU 负载会特别高,最后可能会挂掉
- 因此 Redis 采取的是定期过期,每隔 100ms 就随机抽取一定数量的 key 来检查和删除
- 最后可能会有很多已经过期的 key 没被删除,这时候 Redis 采用惰性删除,在获取某个 key 的时候,Redis 会检查这个 key 如果设置了过期时间并且已经过期了,此时就会删除
⚠️ 注意:如果定期删除漏掉了很多过期的 key,然后也没走惰性删除,就会有很多过期 key 积在内存中,可能会导致内存溢出。为了应对这个问题,Redis 引入了内存淘汰策略进行优化。
3. Redis 内存淘汰策略
内存淘汰策略允许 Redis 在内存资源紧张时,根据一定的策略主动删除一些键值对,以释放内存空间并保持系统的稳定性。
3.1 内存淘汰策略类型
| 策略 | 说明 |
|---|---|
noeviction | 不淘汰策略。当内存不足以容纳新写入数据时,Redis 将新写入的命令返回错误 |
volatile-lru | 从设置了过期时间的键中选择最近最少使用的键进行删除 |
volatile-ttl | 从设置了过期时间的键中选择剩余时间最短的键进行删除 |
volatile-random | 从设置了过期时间的键中随机选择一个键进行删除 |
allkeys-lru | 从所有键中选择最近最少使用的键进行删除 |
allkeys-random | 从所有键中随机选择一个键进行删除 |
4. 缓存击穿、缓存穿透、缓存雪崩
缓存击穿、缓存雪崩和缓存穿透是日常开发与面试过程中必须掌握的常见问题。
4.1 缓存击穿(Cache Breakdown)
4.1.1 什么是缓存击穿?
缓存击穿是指在高并发访问下,一个热点数据失效时,大量请求会直接绕过缓存,直接查询数据库,导致数据库压力剧增。
通常情况下,缓存是为了减轻数据库的负载,提高读取性能而设置的。当某个特定的缓存键(key)失效后,在下一次请求该缓存时,由于缓存中没有对应的数据,因此会去数据库中查询。
4.1.2 解决方案
| 方案 | 说明 |
|---|---|
| 合理的过期时间 | 设置热点数据永不过期,或者设置较长的过期时间,以免频繁失效 |
| 互斥锁 | 当缓存失效时,使用互斥锁保证只有一个线程去查询数据库并更新缓存 |
| 热点数据预加载 | 系统启动时或定时任务预加载热点数据到缓存 |
4.2 缓存穿透(Cache Penetration)
4.2.1 什么是缓存穿透?
缓存穿透是指查询一个不存在的数据,由于缓存中没有该数据,每次请求都会直接查询数据库,而数据库中也没有该数据,导致每次请求都绕过缓存直接访问数据库。
4.2.2 解决方案
| 方案 | 说明 |
|---|---|
| 布隆过滤器 | 在缓存之前加一层布隆过滤器,快速判断 key 是否存在 |
| 缓存空值 | 将不存在的数据也缓存起来,设置较短的过期时间 |
| 参数校验 | 对用户输入进行合法性校验,过滤无效请求 |
4.3 缓存雪崩(Cache Avalanche)
4.3.1 什么是缓存雪崩?
缓存雪崩是指在某一个时间段,缓存集中过期失效,或者 Redis 宕机,导致所有请求都直接访问数据库,数据库压力瞬间增大,甚至宕机。
4.3.2 解决方案
| 方案 | 说明 |
|---|---|
| 过期时间加随机值 | 在设置缓存过期时间时,加上一个随机值,避免大量 key 同时过期 |
| 多级缓存 | 使用本地缓存 + Redis 缓存的多级架构 |
| Redis 高可用 | 使用 Redis 哨兵或集群模式,保证 Redis 服务的高可用 |
| 熔断降级 | 当数据库压力过大时,进行熔断降级,保护数据库 |
4.4 三者对比
| 问题 | 原因 | 特点 |
|---|---|---|
| 缓存击穿 | 热点 key 过期 | 单个热点数据 |
| 缓存穿透 | 查询不存在的数据 | 数据库也没有该数据 |
| 缓存雪崩 | 大量 key 同时过期 / Redis 宕机 | 大面积缓存失效 |
5. Redis 哨兵机制
5.1 为什么需要哨兵机制?
Redis 的主从复制主要用于实现数据的冗余备份和读分担,并不是为了提供高可用性。因此在系统高可用方面,单纯的主从架构无法很好地保证整个系统高可用:
- 需要人工介入:当主节点发生故障时,主从复制无法自动进行主节点的切换,需要管理员手动干预
- 主节点写能力有限:所有写操作都必须发送给主节点处理,主节点成为写入瓶颈
- 单机节点存储能力有限:所有数据都存储在主节点上,存储容量受限
因此通常使用 Redis 哨兵机制或 Redis 集群模式来提高整个系统的可用性、扩展性和负载均衡能力。
5.2 哨兵机制(Sentinel)原理
Redis 哨兵机制是通过在独立的哨兵节点上运行特定的哨兵进程来实现的。这些哨兵进程监控主从节点的状态,并在发现故障时自动完成故障发现和转移。
┌─────────────┐
│ 哨兵集群 │
│ Sentinel │
└──────┬──────┘
│ 监控
┌───────┴───────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Master │ │ Slave │
│ 主节点 │ │ 从节点 │
└─────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ Slave │
│ 从节点 │
└─────────────┘5.3 哨兵选举
在启动时,每个哨兵节点会执行选举过程,其中一个哨兵节点被选为领导者(leader),负责协调其他哨兵节点。
选举过程:
- 每个在线的哨兵节点都可以成为领导者,每个哨兵节点会向其它哨兵发
is-master-down-by-addr命令,征求判断并要求将自己设置为领导者 - 当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者
- 如果哨兵发现自己在选举的票数大于等于
num(sentinels)/2+1时,将成为领导者
5.4 故障转移
一旦主节点被判定为不可用,哨兵节点会执行故障转移操作:
- 发现故障:Sentinel 节点定期监控发现主节点是否出现了故障,sentinel 会向 master 发送心跳 PING 来确认 master 是否存活
- 选择新主节点:
- 过滤掉不健康的(下线或断线),没有回复过哨兵 ping 响应的从节点
- 选择从节点优先级最高的
- 选择复制偏移量最大的从节点(复制最完整的)
- 切换主节点:将选中的从节点提升为新的主节点,并将其他从节点切换到新的主节点
- 通知客户端:哨兵节点会通知客户端新的主节点的位置
5.5 客观下线
当主观下线的节点是主节点时,该哨兵节点会通过指令 sentinel is-master-down-by-addr 寻求其它哨兵节点对主节点的判断,当超过 quorum(选举)个数,此时哨兵节点则认为该主节点确实有问题,这样就客观下线了。
5.6 哨兵机制总结
Redis 哨兵的作用:
- 监控主数据库和从数据库是否正常运行
- 主数据库出现故障时,可以自动将从数据库转换为主数据库,实现自动切换
6. 数据库和缓存一致性问题
6.1 问题来源
使用 Redis 做一个缓冲操作,让请求先访问到 Redis,而不是直接访问 MySQL 等数据库:
客户端 ──▶ Redis 缓存 ──▶ MySQL 数据库
│
▼
读取缓存读取缓存步骤一般没有什么问题,但是一旦涉及到数据更新:数据库和缓存更新,就容易出现缓存(Redis)和数据库(MySQL)间的数据一致性问题。
不管是先写 MySQL 数据库,再删除 Redis 缓存;还是先删除缓存,再写库,都有可能出现数据不一致的情况。
6.2 问题示例
| 方案 | 问题 |
|---|---|
| 先更新 MySQL,再更新 Redis | 如果更新 Redis 失败,可能仍然不一致 |
| 先删除 Redis 缓存,再更新 MySQL | 高并发下性能较低,仍然会出现数据不一致的问题 |
6.3 解决方案
6.3.1 延时双删
先删除 Redis 缓存数据,再更新 MySQL,延迟几百毫秒再删除 Redis 缓存数据,这样就算在更新 MySQL 时,有其他线程读了 MySQL,把老数据读到了 Redis 中,那么也会被删除掉,从而把数据保持一致。
删除缓存 ──▶ 更新数据库 ──▶ 延迟几百毫秒 ──▶ 再次删除缓存6.3.2 队列 + 重试机制
1. 更新数据库数据
2. 缓存因为种种问题删除失败
3. 将需要删除的 key 发送至消息队列(MQ)
4. 自己消费消息,获得需要删除的 key
5. 继续重试删除操作,直到成功缺陷:对业务线代码造成大量的侵入。
6.3.3 异步更新缓存(基于订阅 binlog 的同步机制)
MySQL ──▶ 写入 Binlog ──▶ 订阅 Binlog 程序 ──▶ MQ ──▶ Redis 更新MySQL 中产生了新的写入、更新、删除等操作,就可以把 binlog 相关的消息推送至 Redis,Redis 再根据 binlog 中的记录,对 Redis 进行更新。
实际应用:使用阿里的开源框架 Canal,通过该框架可以对 MySQL 的 binlog 进行订阅,而 Canal 正是模仿了 MySQL 的 slave 数据库的备份请求,使得 Redis 的数据更新达到了相同的效果。
7. Redis 实现分布式锁的 6 种方案
7.1 什么是分布式锁?
分布式锁是一种机制,用于确保在分布式系统中,多个节点在同一时刻只能有一个节点对共享资源进行操作。
分布式锁的特征:
| 特征 | 说明 |
|---|---|
| 互斥性 | 任意时刻,只有一个客户端能持有锁 |
| 锁超时释放 | 持有锁超时,可以释放,防止不必要的资源浪费,也可以防止死锁 |
| 可重入性 | 一个线程如果获取了锁之后,可以再次对其请求加锁 |
| 高性能和高可用 | 加锁和解锁需要开销尽可能低,同时也要保证高可用 |
| 安全性 | 锁只能被持有的客户端删除,不能被其他客户端删除 |
7.2 方案一:SETNX + EXPIRE
提到 Redis 的分布式锁,很多小伙伴马上就会想到 setnx + expire 命令。即先用 setnx 来抢锁,如果抢到之后,再用 expire 给锁设置一个过期时间,防止锁忘记了释放。
SETNX key value # 如果 key 不存在,则设置成功返回 1;如果 key 已存在,返回 0
EXPIRE key 30 # 设置 30 秒过期时间❌ 缺陷:加锁与设置过期时间是非原子操作,如果加锁后未来得及设置过期时间系统异常等,会导致其他线程永远获取不到锁。
7.3 方案二:SETNX + Value 值(系统时间+过期时间)
为了解决方案一「发生异常锁得不到释放的场景」,可以把过期时间放到 setnx 的 value 值里面:
value = 当前系统时间 + 过期时间❌ 缺点:
- 过期时间是客户端自己生成的,必须要求分布式环境下,每个客户端的时间必须同步
- 如果锁过期的时候,并发多个客户端同时请求过来,都执行
jedis.getSet(),最终只能有一个客户端加锁成功,但是该客户端锁的过期时间,可能被别的客户端覆盖 - 该锁没有保存持有者的唯一标识,可能被别的客户端释放/解锁
7.4 方案三:使用 Lua 脚本(包含 SETNX + EXPIRE 两条指令)
使用 Lua 脚本来保证原子性(包含 setnx 和 expire 两条指令):
if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then
redis.call('expire', KEYS[1], ARGV[2])
return 1
else
return 0
end7.5 方案四:SET 的扩展命令(SET EX PX NX)
巧用 Redis 的 SET 指令扩展参数:SET key value [EX seconds] [PX milliseconds] [NX|XX]
| 参数 | 说明 |
|---|---|
NX | 仅当 key 不存在时,才能 set 成功 |
EX seconds | 设定 key 的过期时间,时间单位是秒 |
PX milliseconds | 设定 key 的过期时间,单位为毫秒 |
XX | 仅当 key 存在时设置值 |
SET key value EX 30 NX❌ 可能存在的问题:
- 锁过期释放了,业务还没执行完:假设线程 A 获取锁成功,一直在执行临界区的代码,但是锁过期了,此时线程 B 又请求过来获得锁
- 锁被别的线程误删:假设线程 A 执行完后去释放锁,但它不知道当前的锁可能是线程 B 持有的
解决方案:给 value 值设置一个标记当前线程唯一的随机数,在删除的时候校验:
-- 加锁
SET resource_name my_random_value NX PX 30000
-- 解锁(使用 Lua 脚本保证原子性)
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end7.6 方案五:Redisson 框架
方案四还是可能存在「锁过期释放,业务没执行完」的问题。
Redisson 解决了这个问题:
┌─────────────┐
│ 线程 A │
│ 加锁 LOCK │
└──────┬──────┘
│
▼
┌─────────────┐ ┌─────────────┐
│ Redisson │────▶│ Redis │
│ 看门狗线程 │ │ (Master) │
│ 每10秒检查 │ └─────────────┘
│ 延长锁时间 │
└─────────────┘只要线程一加锁成功,就会启动一个 watch dog 看门狗,它是一个后台线程,会每隔 10 秒检查一下,如果线程 1 还持有锁,那么就会不断的延长锁 key 的生存时间。
7.7 方案六:多机实现的分布式锁 Redlock + Redisson
如果线程一在 Redis 的 master 节点上拿到了锁,但是加锁的 key 还没同步到 slave 节点。恰好这时,master 节点发生故障,一个 slave 节点就会升级为 master 节点。线程二就可以获取同个 key 的锁了,但线程一也已经拿到锁了,锁的安全性就没了。
为了解决这个问题,Redis 作者 antirez 提出一种高级的分布式锁算法:Redlock。
Redlock 核心思想:
搞多个 Redis master 部署(推荐 5 个),以保证它们不会同时宕掉。并且这些 master 节点是完全相互独立的,相互之间不存在数据同步。
Redlock 实现步骤:
- 获取当前时间,以毫秒为单位
- 按顺序向 5 个 master 节点请求加锁。客户端设置网络连接和响应超时时间,并且超时时间要小于锁的失效时间
- 客户端使用当前时间减去开始获取锁时间,得到获取锁使用的时间
- 当且仅当超过一半(N/2+1,这里是 3 个节点)的 Redis master 节点都获得锁,并且使用的时间小于锁失效时间时,锁才算获取成功
- 如果获取锁失败,客户端要在所有的 master 节点上解锁
8. Redis 大 Key 问题
8.1 什么是大 Key?
Redis 没有显式定义大 Key,这是一个通用的术语,用来描述那些在存储和性能方面可能引起问题的键。
大 Key 的判断标准:
| 类型 | 判断标准 |
|---|---|
| String | 单个 key 的 value 大小超过 5MB |
| ZSET | 成员数量超过 1 万个 |
| Hash | 成员数量虽然只有 1K,但成员的 Value 总大小超过 100MB |
8.2 大 Key 引发的问题
- 内存占用过高:大 Key 会占用大量内存,可能导致内存不足
- 阻塞 Redis:删除大 Key 时会导致 Redis 阻塞,影响其他请求
- 网络拥塞:获取大 Key 时会产生大量网络流量
- 主从同步延迟:大 Key 会导致主从复制延迟增加
8.3 如何发现大 Key
# 使用 redis-cli 的 --bigkeys 参数
redis-cli --bigkeys
# 使用 MEMORY USAGE 命令查看 key 的内存占用
MEMORY USAGE key_name8.4 大 Key 的解决方案
| 方案 | 说明 |
|---|---|
| 拆分 | 将大 Key 拆分成多个小 Key |
| 压缩 | 对 value 进行压缩存储 |
| 异步删除 | 使用 UNLINK 命令异步删除大 Key |
| 定期清理 | 设置合理的过期时间,定期清理 |
📌 总结
本文档涵盖了 Redis 面试中的核心知识点:
- 持久化机制:理解 RDB 和 AOF 的原理、优缺点和使用场景
- 过期策略:惰性删除 + 定期删除的组合策略
- 内存淘汰:6 种淘汰策略的特点和选择
- 缓存问题:击穿、穿透、雪崩的区别和解决方案
- 哨兵机制:实现 Redis 高可用的关键
- 一致性:数据库和缓存一致性的解决方案
- 分布式锁:从简单到复杂的 6 种实现方案
- 大 Key:识别和解决大 Key 问题
掌握这些知识点,可以帮助你在面试中更好地展示对 Redis 的深入理解。
