Redis是目前最流行的内存数据库,凭借极高的性能和丰富的数据结构,被广泛应用于缓存、会话存储、消息队列、排行榜、分布式锁等场景。掌握Redis的核心原理和最佳实践,是后端开发者的必备技能。本文将深入介绍Redis的数据结构、应用场景、持久化、集群和性能优化。
一、Redis数据结构与应用场景
| 数据结构 | 特点 | 典型应用场景 |
|---|---|---|
| String | 最基础,最大512M | 缓存、计数器、分布式锁 |
| Hash | 键值对集合 | 对象存储、用户信息 |
| List | 双向链表 | 消息队列、最新列表 |
| Set | 无序唯一集合 | 标签、共同好友、去重 |
| ZSet | 有序唯一集合 | 排行榜、延时队列 |
| Bitmap | 位操作 | 签到、用户在线状态 |
| HyperLogLog | 基数统计 | UV统计(有误差) |
| Stream | 消息流 | 消息队列(5.0+) |
二、缓存设计与穿透防护
缓存三大问题:缓存穿透、缓存击穿、缓存雪崩。
# 缓存穿透:查询不存在的数据,每次都打到数据库
# 解决方案:布隆过滤器 + 缓存空值
# 布隆过滤器
BF.ADD user_filter user_123
BF.EXISTS user_filter user_123
# 缓存空值(设置较短过期时间)
SET user:999 "null" EX 60
# 缓存击穿:热点key过期,大量请求同时打到数据库
# 解决方案:互斥锁 + 逻辑过期
# 互斥锁
SET lock:user:123 "1" EX 10 NX
if 获取锁成功:
查询数据库 → 更新缓存 → 释放锁
else:
等待重试
# 缓存雪崩:大量key同时过期
# 解决方案:过期时间加随机值
EXPIRE user:123 3600 + random(0, 300)
三、分布式锁实现
Redis分布式锁的正确实现方式:
# 加锁(原子操作:SET key value NX EX)
SET lock:order:123 "unique_token" 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_token"
# Redlock算法(多节点,更可靠)
# 向N个Redis节点申请锁,超过半数成功则加锁成功
# 适用于对可靠性要求极高的场景
四、持久化机制
| 机制 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| RDB | 定时快照 | 恢复快、文件小 | 可能丢失最后一次快照后的数据 |
| AOF | 追加写命令 | 数据安全、最多丢1秒 | 文件大、恢复慢 |
| 混合持久化 | RDB+AOF | 兼顾两者优点 | 4.0+支持 |
# redis.conf持久化配置
# RDB
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
# AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # always/everysec/no
# 混合持久化(4.0+)
aof-use-rdb-preamble yes
五、Redis Cluster集群
单节点Redis有内存和性能上限,生产环境通常使用Cluster集群:
- 数据分片:16384个哈希槽分布在多个主节点
- 高可用:每个主节点配置从节点,自动故障转移
- 水平扩展:在线添加/删除节点,自动迁移槽位
- 至少3主3从,6个节点起步
# 创建集群
redis-cli --cluster create
192.168.1.1:6379 192.168.1.2:6379 192.168.1.3:6379
192.168.1.4:6379 192.168.1.5:6379 192.168.1.6:6379
--cluster-replicas 1
# 查看集群状态
redis-cli -c cluster info
redis-cli -c cluster nodes
# 添加节点
redis-cli --cluster add-node 192.168.1.7:6379 192.168.1.1:6379
六、性能优化最佳实践
- 使用批量操作(MGET/MSET/PIPELINE)减少网络往返
- 避免大Key(单个value不超过10KB,集合元素不超过5000)
- 合理设置过期时间,避免内存溢出
- 使用连接池,避免频繁创建连接
- 热key本地缓存,减少Redis压力
- 监控内存使用率、命中率、慢查询
- 设置maxmemory和淘汰策略(allkeys-lru推荐)
# 内存配置
maxmemory 4gb
maxmemory-policy allkeys-lru
# Pipeline批量操作
with r.pipeline() as pipe:
for i in range(1000):
pipe.get(f"key:{i}")
results = pipe.execute()