Redis性能优化全攻略:从内存到架构
一、开场:先澄清场景
Redis 优化没有银弹,要先明确 Redis 的角色 和 瓶颈在哪:
- 纯缓存:可牺牲持久化,优先吞吐和内存
- 存储/消息队列:要兼顾持久化、一致性、可用性
- 瓶颈可能是:内存、CPU、网络、单线程阻塞、热 key、大 key、持久化、主从延迟等
这句话能体现你不是背八股,而是会分析问题。
二、内存优化(最常考)
1. 选对数据结构
- 小对象用 Hash 存字段,比多个 String key 更省内存(底层编码可压缩)
- 排行榜用 ZSet,去重用 Set,计数用 String/INCR
- 避免滥用 String 存 JSON,大对象可考虑 Hash 分字段或压缩
2. 控制 key 设计
- 避免大 key:单个 key 的 value 过大(如百万级 Hash/List),会导致:
- 读写阻塞(Redis 单线程)
- 主从同步慢、AOF rewrite 卡顿
- 内存碎片、淘汰困难
- 避免 key 过多:大量小 key 也有元数据开销
- 合理设置 TTL,防止内存只增不减
3. 内存上限与淘汰策略
maxmemory 4gb maxmemory-policy allkeys-lru # 纯缓存常用 # volatile-lru / allkeys-lfu 等按场景选- 纯缓存:
allkeys-lru/allkeys-lfu - 部分 key 需持久保留:
volatile-lru
4. 编码与配置调优
- 了解 Redis 内部编码(如 listpack、intset),小数据会自动压缩
- 可用
MEMORY USAGE key分析内存占用
三、性能优化(吞吐与延迟)
1. 减少网络往返
- Pipeline:批量发命令,减少 RTT
- MGET/MSET:批量读写
- Lua 脚本:多步操作原子执行,减少往返
2. 避免慢命令
| 危险命令 | 问题 | 替代方案 |
|---|---|---|
KEYS * | O(N) 阻塞 | SCAN游标迭代 |
HGETALL大 Hash | 阻塞 | HSCAN或拆分 |
SMEMBERS大 Set | 阻塞 | SSCAN |
LRANGE 0 -1大 List | 阻塞 | 分页读取 |
3. 连接管理
- 使用 连接池,避免频繁建连
- 合理设置超时、重试,避免连接泄漏
4. 异步删除
- Redis 4.0+ 用
UNLINK替代DEL删除大 key,后台线程异步释放内存
四、热 Key 与大 Key 问题
热 Key(Hot Key)
- 本地缓存(Caffeine/Guava):多级缓存,减轻 Redis 压力
- 读写分离:热 key 读走从库(注意主从延迟)
- key 拆分:如
user:1000→user:1000:0~user:1000:9分散到不同 slot - Redis 6.0+:
redis-cli --hotkeys或监控发现
大 Key(Big Key)
- 拆分:大 Hash 按 field 范围拆成多个 key
- 压缩:value 序列化后 gzip
- 定期清理:
SCAN+UNLINK分批删除 - 排查:
redis-cli --bigkeys、MEMORY USAGE
五、持久化优化
| 场景 | 建议 |
|---|---|
| 纯缓存 | 可关闭 RDB/AOF |
| 可接受分钟级丢失 | RDB(快照) |
| 需高可靠 | AOF +appendfsync everysec |
| 兼顾性能与可靠 | Redis 4.0+ 混合持久化(RDB + AOF 增量) |
注意:
- AOF rewrite 会 fork,大内存实例可能卡顿
- 可设
auto-aof-rewrite-percentage控制 rewrite 频率
六、架构与高可用
1. 水平扩展
- Redis Cluster:16384 slot 分片,突破单机内存/吞吐
- 注意:跨 slot 的 multi-key 操作 受限(可用 hash tag
{user}:1000)
2. 读写分离
- 主写从读,注意 主从延迟 导致读到旧数据
- 强一致读需走主库
3. 高可用
- Sentinel:主从 + 自动故障转移
- Cluster:分片 + 高可用
七、监控与排查
- slowlog:
SLOWLOG GET查慢命令 - latency doctor:延迟诊断
- INFO memory/stats:内存、命中率、连接数
- redis-exporter + Prometheus + Grafana:持续监控
- 关注:命中率、evicted_keys、blocked_clients、used_memory_rss(碎片)
八、回答模板(可直接背)
Redis 优化我会从几个层面看:
- 内存:选对数据结构、控制 key 大小和数量、设 maxmemory 和淘汰策略、合理 TTL
- 性能:Pipeline 减 RTT、避免 KEYS/HGETALL 等慢命令、用 UNLINK 删大 key、连接池
- 热点:热 key 用本地缓存或 key 拆分,大 key 拆分或压缩
- 持久化:纯缓存可关;要可靠用 AOF 或混合持久化,并控制 rewrite
- 架构:单机不够就 Cluster 分片,读多就主从读写分离
- 监控:slowlog、bigkeys、hotkeys、命中率,先定位再优化
九、常见追问及简答
| 追问 | 要点 |
|---|---|
| LRU 和 LFU 区别? | LRU 看时间,LFU 看频率;LFU 对热 key 更友好 |
| 为什么 Redis 单线程还快? | 纯内存、IO 多路复用、无锁、简单数据结构 |
| 热 key 导致单点打满怎么办? | 本地缓存 + key 拆分 + 多副本 |
| 如何保证缓存与 DB 一致? | 先更新 DB 再删缓存、延迟双删、Canal 订阅 binlog |
| Cluster 如何分片? | CRC16(key) % 16384 得到 slot |