Redis面试题整理

Zset

压缩列表

当元素数量 ≤ zset-max-ziplist-entries(默认128)且所有元素长度 ≤ zset-max-ziplist-value(默认64字节)时使用,内存紧凑。

跳表

采用多级索引;插入、删除、范围查找的时间复杂度都是O(logN)

字典:存储 member→score 的映射,实现 O(1) 的分数查找。

比红黑树的优点:范围查找更简单。

跳表插入索引的步骤:

  1. 随机决定它的层高(Redis 默认最大 32 层)
  2. 从最高层开始,向右遍历找到每一层的插入点
  3. 在各层插入新节点

多级缓存

多级缓存 = 本地缓存(Caffeine) + 分布式缓存(Redis) + 数据库

Redis 事务

  1. 执行方式:批量执行(非原子性)
  • MULTI:开启事务,后续命令会放入队列,但不会立即执行。

  • EXEC:执行队列中的所有命令。

  • DISCARD:取消事务,清空队列。

  1. 没有隔离级别(单线程模型)
  2. Redis 事务不支持回滚,如果某条命令失败,Redis 不会自动撤销已执行的命令。
  3. WATCH key:监视一个 key,如果在 EXEC 前 key 被其他客户端修改,事务会失败。
1
2
3
4
5
6
> WATCH balance    # 监视 balance
OK
> MULTI
> DECRBY balance 100
QUEUED
> EXEC             # 如果 balance 被其他客户端修改过,这里返回 (nil)

一致性

与数据库一致性

  1. 延迟双删
  2. 使用 Canal 或 Debezium 监听 MySQL Binlog,实时同步到 Redis。

Redis 集群数据一致性

主从同步:主节点(Master)异步复制数据到从节点(Slave),存在短暂延迟。

Redis Sentinel:自动故障转移,但切换期间可能丢数据。

Redis Cluster:分片存储,通过 Gossip 协议同步状态,但不保证强一致性。

Redis 内存不够

内存淘汰策略

  1. allkeys-lru:淘汰最近最少使用的 key,适合通用场景
  2. volatile-lru:仅淘汰有过期时间的 LRU key,适合缓存场景
  3. volatile-ttl:优先淘汰即将过期的键
  4. no-eviction:内存不够时,对新写入的命令返回错误。
  5. allkeys-lfu: 从所有键中淘汰最不经常使用(LFU) 的键(Redis 4.0+)

惰性删除(Lazy Free)

Redis 默认使用 惰性删除 + 定期删除 组合策略:

  • 惰性删除:当读取一个过期 key 时,才检查并删除。缺点是浪费内存。

  • 定期删除:Redis 每100 毫秒随机扫描设置了过期时间的 key,清理过期数据。

  • 大 key 用 UNLINK(异步删除)替代 DEL。

Redis原子性

  1. SETNX, INCR / DECR,原生原子命令
  2. 事务:MULTI/EXEC,无隔离性,不支持回滚;WATCH监听key,乐观锁
  3. Lua脚本

大key问题

  1. 定义: string 的value超过1M;复合类型的 value 包含的元素超过 5000 个
  2. 发现大key
  • –bigkeys命令。需要扫描所有的key,并且只能找到每种数据结构最大的 key。
  • SCAN 命令。按模式返回对应的 key,再用STRLEN、HLEN命令获得其长度。
  • rdb_bigkeys开源工具分析RDB文件。
  1. 处理大key:
  • 分割:将一个含有上万字段数量的 Hash 按照一定策略(比如二次哈希)拆分为多个 Hash。
  • 删除:UNLINK 命令来异步删除一个或多个指定的 key