概述
Redis(Remote Dictionary Server)是基于内存的高性能 key-value 数据库,支持丰富的数据结构,广泛用于缓存、消息队列、分布式锁等场景。
数据类型
基本类型
| 类型 |
底层结构 |
典型场景 |
| String |
SDS |
缓存、计数器、分布式锁 |
| List |
quicklist(ziplist + 链表) |
消息队列、最新列表 |
| Hash |
ziplist / hashtable |
对象存储、购物车 |
| Set |
intset / hashtable |
去重、交集并集运算、标签 |
| ZSet |
ziplist / skiplist + hashtable |
排行榜、延迟队列 |
特殊类型
- Bitmap:位操作,签到统计
- HyperLogLog:基数估算,UV 统计
- GEO:地理位置,附近的人
- Stream:消息队列(5.0+)
持久化
RDB(快照)
- 定时将内存数据快照写入磁盘
- 优点:恢复速度快,文件紧凑
- 缺点:可能丢失最后一次快照后的数据
# 配置
save 900 1 # 900秒内至少1次修改则触发
save 300 10
save 60 10000
AOF(Append Only File)
- 每次写操作追加到日志文件
- 三种刷盘策略:
- always:每条命令都刷盘(最安全,最慢)
- everysec:每秒刷盘(推荐)
- no:由操作系统决定
混合持久化(4.0+)
- RDB + AOF 结合
- 重写时以 RDB 格式写入基础数据,增量部分用 AOF
内存淘汰策略
| 策略 |
说明 |
| noeviction |
默认,内存满时拒绝写入 |
| allkeys-lru |
所有 key 中淘汰最近最少使用 |
| allkeys-lfu |
所有 key 中淘汰最不经常使用(4.0+) |
| volatile-lru |
设了过期时间的 key 中 LRU |
| volatile-lfu |
设了过期时间的 key 中 LFU |
| allkeys-random |
随机淘汰 |
| volatile-random |
过期 key 中随机淘汰 |
| volatile-ttl |
淘汰 TTL 最短的 |
集群方案
主从复制
- 全量同步 + 增量同步(repl_backlog)
- 从节点只读
哨兵模式(Sentinel)
Cluster 模式
- 数据分片(16384 个 hash slot)
- 节点间 Gossip 协议通信
- 每个 key 通过
CRC16(key) % 16384 计算所属 slot
常见应用场景
分布式锁
# 加锁
SET lock:order:123 "unique_value" NX EX 30
# 释放锁(Lua 脚本保证原子性)
EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock:order:123 "unique_value"
生产环境推荐使用 Redisson 实现分布式锁。
缓存击穿/穿透/雪崩
| 问题 |
原因 |
解决方案 |
| 缓存穿透 |
查询不存在的数据 |
布隆过滤器、缓存空值 |
| 缓存击穿 |
热点 key 过期 |
互斥锁、热点 key 永不过期 |
| 缓存雪崩 |
大量 key 同时过期 |
过期时间加随机值、多级缓存 |
其他场景
- 排行榜:ZSet + ZRANGEBYSCORE
- 计数器:INCR / INCRBY
- 消息队列:List + BRPOP / Stream
- 限流:滑动窗口(ZSet)/ 令牌桶
Redisson
特点
- 基于 Netty 的 Redis Java 客户端
- 提供分布式锁、限流器、布隆过滤器等高级功能
- 支持多种锁:可重入锁、公平锁、读写锁、红锁
Watchdog 机制
- 默认 30 秒锁过期
- 后台线程每 10 秒续期,防止业务未完成锁过期
常见面试题
- Redis 为什么快?
- Redis 的持久化方式?如何选择?
- 缓存穿透、击穿、雪崩的解决方案?
- Redis Cluster 的分片原理?
- 如何实现一个分布式锁?
参考资料