1高级特性
1 过期策略
Redis 采用「惰性删除 + 定期删除」的策略:
- 惰性删除:访问 key 时检查是否过期
- 定期删除:周期性随机检查一部分 key 并删除
2 内存淘汰策略
当内存达到上限时,根据 maxmemory-policy 配置的策略淘汰数据:
| 策略 | 说明 |
|---|---|
| noeviction | 不淘汰,写操作报错(默认) |
| allkeys-lru | 对所有 key 使用 LRU 淘汰 |
| allkeys-lfu | 对所有 key 使用 LFU 淘汰 |
| allkeys-random | 随机淘汰 |
| volatile-lru | 对设置了过期时间的 key 使用 LRU |
| volatile-ttl | 淘汰剩余 TTL 最短的 key |
3 分布式锁
# 加锁(NX 表示不存在才设置)
SET lock_key unique_value NX PX 30000
# 解锁(使用 Lua 脚本保证原子性)
EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock_key unique_value
4 Pipeline(管道)
批量执行命令,减少网络往返。
import redis
r = redis.Redis(host='localhost', port=6379)
pipe = r.pipeline()
for i in range(1000):
pipe.set(f'key{i}', i)
pipe.execute()
2. 持久化
2.1 RDB(快照)
将某个时间点的数据快照保存到磁盘。
# redis.conf 配置
save 900 1 # 900 秒内至少 1 次修改触发保存
save 300 10 # 300 秒内至少 10 次修改
save 60 10000 # 60 秒内至少 10000 次修改
dbfilename dump.rdb
优点:文件紧凑,适合备份和灾难恢复
缺点:可能丢失最后一次快照后的数据
2.2 AOF(追加文件)
记录每次写操作命令。
appendonly yes
appendfilename "appendonly.aof"
appendfsync always # 每次写都同步,最安全但最慢
appendfsync everysec # 每秒同步一次(默认,推荐)
appendfsync no # 由操作系统决定
优点:数据更安全,丢失少
缺点:文件更大,恢复慢
2.3 混合持久化(推荐)
aof-use-rdb-preamble yes
3. 主从复制与哨兵
3.1 主从复制
# 从节点配置
replicaof <master-ip> <master-port>
# 查看复制状态
redis-cli info replication
3.2 哨兵(Sentinel)
监控主节点,主节点宕机时自动故障转移。
# sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel auth-pass mymaster password
redis-sentinel sentinel.conf
4. 集群
Redis Cluster 提供数据分片和高可用。
# 创建集群(3 主 3 从)
redis-cli --cluster create \
127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
5. 性能优化与常见问题
5.1 性能优化建议
- 使用合适的数据结构,避免大 key 和热 key
- 使用 Pipeline 批量操作
- 避免使用
KEYS命令,使用SCAN - 合理设置过期时间和内存淘汰策略
- 关闭
THP(透明大页) - 使用连接池
5.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 缓存穿透 | 查询不存在的数据 | 布隆过滤器、缓存空值 |
| 缓存击穿 | 热点 key 过期瞬间大量请求 | 互斥锁、逻辑过期 |
| 缓存雪崩 | 大量 key 同时过期 | 过期时间加随机值 |
| 大 key | 单个 key 数据过大 | 拆分 key |
6. python语言客户端使用示例
Python
pip install redis
import redis
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
# String
r.set('name', 'zhangsan')
print(r.get('name'))
# Hash
r.hset('user:1', mapping={'name': 'zhangsan', 'age': 20})
print(r.hgetall('user:1'))
# 过期时间
r.setex('token', 3600, 'abc123')