1. Redis 是什么
Redis 是一个基于内存的高性能 Key-Value 数据库,常用于:
- 缓存
- 分布式锁
- 排行榜
- 计数器
- 消息队列
- 会话存储
- 限流
- 延迟任务
- 实时统计
Redis 的核心特点:
- 数据主要存储在内存中,速度快
- 支持丰富的数据结构
- 单线程处理命令,避免复杂锁竞争
- 支持持久化、主从复制、哨兵、集群
- 支持 Lua 脚本保证原子操作
2. 常见数据结构
Redis 不只是简单的字符串缓存,它支持多种数据结构。
String
最基础类型,可以存字符串、数字、JSON。
常用场景:
- 缓存对象
- 计数器
- 分布式锁
- Token 存储
常用命令:
vbnet
SET key value
GET key
INCR key
DECR key
SETEX key seconds value
SETNX key value
Hash
类似 Map,适合存对象字段。
场景:
- 用户信息
- 商品信息
- 配置对象
sql
HSET user:1 name tom age 18
HGET user:1 name
HGETALL user:1
HINCRBY user:1 age 1
List
双向链表,支持左右插入和弹出。
场景:
- 消息队列
- 最新列表
- 简单任务队列
arduino
LPUSH queue task1
RPOP queue
LRANGE list 0 -1
Set
无序集合,元素唯一。
场景:
-
去重
-
标签
-
共同好友
-
抽奖
SADD tags java redis
SMEMBERS tags
SINTER set1 set2
SUNION set1 set2
ZSet
有序集合,每个元素带 score。
场景:
-
排行榜
-
热度榜
-
延迟队列
-
权重排序
ZADD rank 100 user1
ZRANGE rank 0 -1 WITHSCORES
ZREVRANGE rank 0 9 WITHSCORES
Bitmap
位图,本质上是 String 的位操作。
场景:
- 用户签到
- 活跃统计
- 布隆过滤器底层实现之一
r
SETBIT sign:202606 1 1
GETBIT sign:202606 1
BITCOUNT sign:202606
HyperLogLog
用于大规模去重统计,结果是近似值。
场景:
-
UV 统计
-
大规模唯一用户数统计
PFADD uv user1 user2
PFCOUNT uv
Stream
Redis 5.0 引入的消息流结构。
场景:
-
消息队列
-
日志流
-
事件流
XADD stream * name tom
XREAD COUNT 10 STREAMS stream 0
3. Redis 为什么快
主要原因:
- 数据在内存中
- 单线程执行命令,减少线程切换和锁竞争
- 使用 I/O 多路复用处理网络连接
- 数据结构设计高效
- C 语言实现,执行效率高
注意:Redis 的"单线程"主要指命令执行是单线程。新版本 Redis 在网络 I/O、异步删除、持久化等方面也会使用多线程。
4. Redis 持久化
Redis 支持两种主要持久化方式。
RDB
定期生成内存快照。
优点:
- 文件紧凑
- 恢复速度快
- 适合备份
缺点:
- 可能丢失最近一次快照后的数据
AOF
记录每一条写命令。
优点:
- 数据更安全
- 可配置每秒刷盘
缺点:
- 文件通常比 RDB 大
- 恢复速度可能比 RDB 慢
常见刷盘策略:
perl
appendfsync always
appendfsync everysec
appendfsync no
生产环境常用:
RDB + AOF
5. 过期策略和淘汰策略
Redis 可以给 Key 设置过期时间。
vbnet
EXPIRE key seconds
TTL key
过期删除策略:
- 惰性删除:访问 key 时发现过期再删除
- 定期删除:Redis 定期扫描部分过期 key
内存淘汰策略常见有:
noeviction:内存满了直接报错allkeys-lru:从所有 key 中淘汰最近最少使用volatile-lru:从设置了过期时间的 key 中淘汰 LRUallkeys-random:随机淘汰volatile-ttl:优先淘汰快过期的 keyallkeys-lfu:淘汰使用频率低的 key
缓存场景常用:
allkeys-lru
allkeys-lfu
6. 缓存常见问题
缓存穿透
查询不存在的数据,请求直接打到数据库。
解决方案:
- 缓存空值
- 使用布隆过滤器
- 参数校验
缓存击穿
热点 key 过期,大量请求同时打到数据库。
解决方案:
- 互斥锁
- 热点 key 不过期
- 逻辑过期
- 提前异步刷新
缓存雪崩
大量 key 同时过期或 Redis 故障。
解决方案:
- 过期时间加随机值
- 多级缓存
- Redis 高可用
- 限流降级
7. Redis 分布式锁
常见实现:
sql
SET lock_key unique_value NX EX 30
释放锁时必须校验 value,避免误删别人的锁。
通常用 Lua 脚本保证原子性:
vbnet
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
注意点:
- 锁必须设置过期时间
- value 必须唯一
- 删除锁要校验 owner
- 业务执行时间可能超过锁过期时间
- 高可靠场景可考虑 Redisson
8. 主从、哨兵、集群
主从复制
一个 Master,多个 Replica。
作用:
- 读写分离
- 数据备份
- 提升读能力
问题:
- 主节点挂了需要人工或机制切换
Sentinel 哨兵
用于监控 Redis 主从,并自动故障转移。
功能:
- 监控节点
- 主观下线、客观下线
- 自动选举新 Master
- 通知客户端新地址
Cluster 集群
Redis Cluster 用于分片存储数据。
特点:
- 共有 16384 个 hash slot
- 每个 key 映射到一个 slot
- slot 分布在多个节点上
- 支持水平扩展
- 节点之间通过 Gossip 通信
9. Redis 事务和 Lua
Redis 事务使用:
css
MULTI
SET a 1
INCR b
EXEC
特点:
- 命令按顺序执行
- 不支持传统数据库那种回滚
- 可配合
WATCH做乐观锁
Lua 脚本优势:
- 多条命令原子执行
- 减少网络往返
- 适合分布式锁、限流、库存扣减等场景
10. Redis 常见使用场景
缓存对象:
sql
SETEX user:1 3600 "{...}"
计数器:
css
INCR article:1:views
排行榜:
ZINCRBY rank 1 user1
限流:
sql
INCR rate:user:1
EXPIRE rate:user:1 60
消息队列:
arduino
LPUSH queue msg
RPOP queue
延迟队列:
sql
ZADD delay_queue timestamp task
分布式锁:
sql
SET lock:order:1 uuid NX EX 30
11. 面试重点
高频问题:
- Redis 为什么快?
- Redis 单线程为什么还能高并发?
- RDB 和 AOF 区别?
- Redis 如何实现分布式锁?
- 缓存穿透、击穿、雪崩怎么解决?
- Redis 的过期删除策略是什么?
- Redis 内存淘汰策略有哪些?
- Redis 主从复制过程?
- Sentinel 和 Cluster 的区别?
- Redis Cluster 为什么是 16384 个槽?
- Redis 事务是否支持回滚?
- ZSet 底层结构是什么?
- Redis 和 MySQL 如何保证缓存一致性?
12. 一句话总结
Redis 的核心是:基于内存的高性能数据结构服务器,围绕缓存、持久化、高可用、分布式场景解决系统性能和可扩展性问题。