Redis面试题整理
Zset
压缩列表
当元素数量 ≤ zset-max-ziplist-entries(默认128)且所有元素长度 ≤ zset-max-ziplist-value(默认64字节)时使用,内存紧凑。
跳表
采用多级索引;插入、删除、范围查找的时间复杂度都是O(logN)
字典:存储 member→score 的映射,实现 O(1) 的分数查找。
比红黑树的优点:范围查找更简单。
跳表插入索引的步骤:
- 随机决定它的层高(Redis 默认最大 32 层)
- 从最高层开始,向右遍历找到每一层的插入点
- 在各层插入新节点
多级缓存
多级缓存 = 本地缓存(Caffeine) + 分布式缓存(Redis) + 数据库
Redis 事务
- 执行方式:批量执行(非原子性)
MULTI:开启事务,后续命令会放入队列,但不会立即执行。
EXEC:执行队列中的所有命令。
DISCARD:取消事务,清空队列。
- 没有隔离级别(单线程模型)
- Redis 事务不支持回滚,如果某条命令失败,Redis 不会自动撤销已执行的命令。
- WATCH key:监视一个 key,如果在 EXEC 前 key 被其他客户端修改,事务会失败。
|
|
一致性
与数据库一致性
- 延迟双删
- 使用 Canal 或 Debezium 监听 MySQL Binlog,实时同步到 Redis。
Redis 集群数据一致性
主从同步:主节点(Master)异步复制数据到从节点(Slave),存在短暂延迟。
Redis Sentinel:自动故障转移,但切换期间可能丢数据。
Redis Cluster:分片存储,通过 Gossip 协议同步状态,但不保证强一致性。
Redis 内存不够
内存淘汰策略
- allkeys-lru:淘汰最近最少使用的 key,适合通用场景
- volatile-lru:仅淘汰有过期时间的 LRU key,适合缓存场景
- volatile-ttl:优先淘汰即将过期的键
- no-eviction:内存不够时,对新写入的命令返回错误。
- allkeys-lfu: 从所有键中淘汰最不经常使用(LFU) 的键(Redis 4.0+)
惰性删除(Lazy Free)
Redis 默认使用 惰性删除 + 定期删除 组合策略:
惰性删除:当读取一个过期 key 时,才检查并删除。缺点是浪费内存。
定期删除:Redis 每100 毫秒随机扫描设置了过期时间的 key,清理过期数据。
大 key 用 UNLINK(异步删除)替代 DEL。
Redis原子性
- SETNX, INCR / DECR,原生原子命令
- 事务:MULTI/EXEC,无隔离性,不支持回滚;WATCH监听key,乐观锁
- Lua脚本
大key问题
- 定义: string 的value超过1M;复合类型的 value 包含的元素超过 5000 个
- 发现大key
- –bigkeys命令。需要扫描所有的key,并且只能找到每种数据结构最大的 key。
- SCAN 命令。按模式返回对应的 key,再用STRLEN、HLEN命令获得其长度。
- rdb_bigkeys开源工具分析RDB文件。
- 处理大key:
- 分割:将一个含有上万字段数量的 Hash 按照一定策略(比如二次哈希)拆分为多个 Hash。
- 删除:UNLINK 命令来异步删除一个或多个指定的 key