Redis高频面试题汇总:从基础到高级全覆盖
一、基础概念篇
1.1 Redis核心定义与特性
Redis(Remote Dictionary Server) 是一个开源的、基于内存的高性能键值存储系统,支持多种数据结构(字符串、哈希、列表、集合、有序集合等),具备持久化、高可用、分布式扩展等特性。其核心优势体现在:
极致性能:单线程模型结合内存存储,读写速度达11万次/秒(读)和8万次/秒(写),远超传统磁盘数据库。
丰富数据结构:支持五种基础数据结构及高级模块(如HyperLogLog、Geo、BloomFilter),满足多样化业务场景。
持久化机制:通过RDB快照和AOF日志实现数据持久化,保障故障恢复能力。
高可用架构:主从复制、哨兵模式和集群模式支持自动故障转移,确保服务连续性。
1.2 Redis与Memcached的核心区别
| 对比维度 | Redis | Memcached |
|---|---|---|
| 数据结构 | 支持复杂类型(哈希、列表等) | 仅支持简单键值对 |
| 持久化 | 支持RDB/AOF持久化 | 无持久化能力 |
| 线程模型 | 单线程(Redis 6.0前) | 多线程 |
| 集群支持 | 原生支持集群模式 | 需依赖客户端实现分片 |
| 内存管理 | 支持数据过期淘汰和LRU策略 | 仅支持LRU淘汰 |
| 适用场景 | 缓存、消息队列、分布式锁等 | 简单缓存场景 |
典型面试题:
Q:为什么Redis选择单线程模型仍能保持高性能?
A:
内存操作:所有数据存储在内存中,避免磁盘I/O延迟。
IO多路复用:基于epoll/kqueue实现非阻塞网络IO,单线程高效处理大量连接。
避免锁竞争:单线程消除多线程切换和锁开销,保证原子性操作。
高效数据结构:哈希表、跳表等设计使操作时间复杂度为O(1)或O(logN)。
二、数据结构与高级特性
2.1 五大核心数据结构详解
字符串(String)
场景:缓存用户信息、计数器、分布式锁。
示例:
SETuser:1001"{\"name\":\"Alice\",\"age\":25}"EX3600#存储JSON对象并设置过期时间 INCRviews:page1#原子递增计数器
哈希(Hash)
场景:存储对象属性(如用户信息、商品详情)。
优势:避免序列化开销,支持字段级操作。
示例:
HSETproduct:100"price"99.9"stock"100#存储商品价格和库存 HINCRBYproduct:100"stock"-1#减少库存
列表(List)
场景:消息队列、最新消息排序、分页查询。
操作:
LPUSHmessages"msg1""msg2"#从左侧插入消息 BRPOPmessages0#阻塞式从右侧弹出消息(超时时间0表示无限等待)
集合(Set)
场景:标签系统、共同关注、去重。
运算:
SADDtags:article1"tech""redis"#添加标签 SINTERtags:article1tags:article2#获取两篇文章的共同标签
有序集合(Sorted Set)
场景:排行榜、优先级队列、范围查询。
示例:
ZADDleaderboard1000"Alice"950"Bob"#添加分数和用户 ZREVRANGEleaderboard02WITHSCORES#获取前三名(降序)
2.2 高级特性与模块
HyperLogLog
用途:基数统计(如UV计算),仅需12KB内存即可估算2^64个元素的基数。
示例:
PFADDuv:20250811"user1""user2""user3"#添加用户 PFCOUNTuv:20250811#获取独立用户数
Geo
用途:地理位置存储与查询(如附近的人、外卖配送范围)。
示例:
GEOADDlocations116.40439.915"Beijing"#添加经纬度坐标 GEORADIUSlocations116.40439.91510km#查询10公里内的地点
Redis Stream
用途:消息队列(支持消费者组、消息回溯)。
示例:
XADDorders*item"book"quantity2#添加消息 XREADGROUPGROUPgroup1consumer1COUNT1STREAMSorders>#消费者组读取消息
三、持久化与高可用
3.1 持久化机制对比
| 机制 | RDB(快照) | AOF(日志) |
|---|---|---|
| 原理 | 定期生成内存数据二进制快照 | 记录所有写操作命令 |
| 优点 | 文件紧凑、恢复速度快 | 数据安全性高、支持秒级持久化 |
| 缺点 | 可能丢失最后一次快照后的数据 | 文件体积大、恢复速度慢 |
| 适用场景 | 对性能要求高,容忍少量数据丢失 | 对数据安全性要求高 |
混合持久化(Redis 4.0+):结合RDB和AOF优势,生成RDB格式的全量数据+AOF格式的增量日志,平衡恢复速度与数据安全性。
3.2 高可用架构设计
主从复制(Master-Slave)
原理:主节点处理写操作,异步同步到从节点;从节点仅处理读操作。
配置:
SLAVEOF192.168.1.1006379#将当前节点设为从节点
哨兵模式(Sentinel)
功能:监控主从节点健康状态,自动故障转移。
工作流程:
哨兵集群定期检查主节点存活状态。
主节点故障时,通过Raft算法选举新的主节点。
更新从节点配置,指向新主节点。
集群模式(Cluster)
分片机制:使用哈希槽(16384个槽)分配数据,每个节点负责部分槽位。
扩容:通过
CLUSTER MEET命令添加新节点,使用CLUSTER ADDSLOTS重新分配槽位。故障处理:当多数主节点无法联系时,集群进入不可用状态。
四、性能优化与故障排查
4.1 常见性能问题与解决方案
大Key问题
现象:单个Key存储数据量过大(如百万级元素的列表),导致读写延迟高、内存不均。
解决方案:
拆分:将大Key拆分为多个小Key(如
user:1001:orders:1、user:1001:orders:2)。压缩:使用ZSTD等压缩算法存储数据。
异步加载:分页查询大列表,避免一次性加载全部数据。
热点Key问题
现象:某些Key被高频访问,导致单节点负载过高。
解决方案:
本地缓存:在应用层使用Guava Cache缓存热点数据。
多级缓存:结合Redis和本地缓存,减少对Redis的直接访问。
读写分离:主节点写,从节点读,分散读压力。
慢查询问题
现象:执行时间超过阈值的命令阻塞Redis。
排查工具:
SLOWLOGGET10#获取最近10条慢查询日志
优化策略:
避免使用
KEYS命令,改用SCAN渐进式遍历。优化复杂命令(如
SORT、SUNION),拆分为多个简单命令。
4.2 内存淘汰策略
| 策略 | 描述 |
|---|---|
noeviction | 默认策略,内存满时禁止写入,返回错误。 |
volatile-lru | 从设置了过期时间的键中淘汰最近最少使用(LRU)的键。 |
allkeys-random | 从所有键中随机淘汰。 |
volatile-ttl | 优先淘汰剩余生存时间(TTL)最短的键。 |
配置示例:
CONFIGSETmaxmemory-policyvolatile-lru#设置内存淘汰策略
五、分布式与实战场景
5.1 分布式锁实现
基于SETNX的简单实现
SETlock:order123"1"NXEX10#原子操作:仅当key不存在时设置,并设置10秒过期时间
问题:未处理锁续期和误删问题。
Redisson改进方案
看门狗机制:自动续期锁,防止业务未执行完锁过期。
Lua脚本释放锁:保证原子性,避免误删其他客户端的锁。
代码示例:
RLocklock=redisson.getLock("orderLock"); lock.lock(30,TimeUnit.SECONDS);//自动续期 try{ //业务逻辑 }finally{ lock.unlock(); }
5.2 缓存一致性策略
Cache Aside Pattern(旁路缓存)
读流程:先查缓存,未命中则查数据库,写入缓存。
写流程:先更新数据库,再删除缓存(而非更新缓存,避免复杂一致性维护)。
问题:并发场景下可能存在缓存不一致(如线程A更新数据库但未删缓存时,线程B读取旧数据并写入缓存)。
延迟双删策略
publicvoidupdateData(Datadata){
redis.del(data.getId());//第一次删除缓存
db.update(data);//更新数据库
Thread.sleep(1000);//延时1秒
redis.del(data.getId());//第二次删除缓存
}原理:通过延时删除覆盖可能存在的脏数据写入。
六、监控与运维
6.1 监控指标与工具
| 指标 | 工具 | 阈值建议 |
|---|---|---|
| 内存使用率 | INFO memory | >80%时触发告警 |
| 命中率 | INFO stats |
推荐阅读
-
JAVA实现HTML转PDF的五种方法详解
-
MySQL创建和删除索引命令CREATE/DROP INDEX使用方法详解
-
深入理解 JavaScript 原型和构造函数创建对象的机制
-
ZooKeeper和Eureka有什么区别?注册中心如何选择?
-
ZooKeeper是什么?分布式系统开发者必读入门指南
-
JavaScript防抖与节流函数怎么写?高频事件优化技巧详解
-
c++中sprintf函数使用方法及示例代码详解
在C++编程中,格式化输出是常见的需求。虽然cout提供了基本的输出功能,但在需要精确控制输出格式(如指定宽度、精度、进制等)...
-
Swagger 接口注解详解教程:@Api、@ApiOperation、@ApiModelProperty 全解析
-
Python变量命名规则全解析:打造规范、可读性强的代码风格
-
OpenSSL是什么?OpenSSL使用方法详解

