04 性能优化与最佳实践
进阶篇最后一章:把散落在前面各章的"避坑要点"汇总成一份清单,再补充几个生产环境的实用技巧。 建议工作后回来重读本章,感受会完全不同。
1. 避免慢命令(Redis 是单线程,一条慢命令卡住所有人)
| 危险命令 | 问题 | 替代方案 |
|---|---|---|
keys * | 遍历所有 key,阻塞 | scan 分批遍历 |
flushall / flushdb | 清库,阻塞且毁灭性 | 生产环境用 rename-command 禁用 |
hgetall / smembers / lrange key 0 -1(大 key 时) | 一次取几十万元素 | hscan / sscan / 分页 lrange |
del 大key | 删除大集合同步阻塞 | unlink(异步删除) |
| 复杂 Lua / 大事务 | 执行期间独占 | 拆小、控制循环次数 |
排查慢命令用慢查询日志:
config set slowlog-log-slower-than 10000 # 记录超过 10ms 的命令
slowlog get 10 # 查看最近 10 条慢命令
2. 警惕大 Key(Big Key)
大 key 指 value 特别大的 key:如 10MB 的 String、百万成员的 ZSet/Hash。
危害:读写慢、删除阻塞、网络带宽被打满、集群下数据倾斜(某节点特别撑)。
发现:
redis-cli --bigkeys # 扫描统计各类型最大的 key
memory usage somekey # 查看单个 key 的内存占用
治理思路:
- 拆分:一个百万成员的 Hash 拆成
key:0~key:99共 100 个小 Hash(按成员 hash 取模分配) - 压缩:JSON 先压缩再存
- 删除大 key 用
unlink而不是del
预防:设计阶段就约定——单 key 的 String 不超过 10KB,集合类成员不超过 5000(经验值,非硬性)。
3. 警惕热 Key(Hot Key)
热 key 指访问量极高的单个 key(顶流明星官宣、秒杀商品)。集群再大也没用——一个 key 只在一个节点上,那个节点会被单点打爆。
方案:
- 本地缓存:热 key 在应用进程内也缓存一份(Caffeine/Guava),挡掉绝大部分请求
- key 打散:
hot:key复制成hot:key:1~hot:key:10存到不同节点,读时随机挑一个
4. 批量操作:管道(Pipeline)
循环里逐条发命令,1 万条 = 1 万次网络往返,大量时间浪费在路上。Pipeline 把一批命令打包一次发出,性能提升可达几十倍:
# 慢:1 万次网络往返
for i in range(10000):
r.set(f"key:{i}", i)
# 快:打包发送
pipe = r.pipeline()
for i in range(10000):
pipe.set(f"key:{i}", i)
pipe.execute()
注意:Pipeline 只是省网络往返,不保证原子性(和事务、Lua 是不同的东西);一批别塞太多,几百到几千条一批合适。
5. 安全清单(云服务器必看)
裸奔的公网 Redis 几分钟就会被入侵。上线前逐项检查:
requirepass 强密码 # 1. 必须设密码
bind 127.0.0.1 内网IP # 2. 只监听内网,不暴露公网
protected-mode yes # 3. 保护模式保持开启
rename-command FLUSHALL "" # 4. 禁用危险命令
rename-command CONFIG ""
port 16379 # 5. (可选)换掉默认端口
外加:防火墙/安全组只放行内网、Redis 进程不要用 root 运行、Redis 6+ 可用 ACL 精细控制权限(acl setuser ...)。
6. 键设计与使用习惯清单
- ✅ key 命名
业务:对象:id:属性,全项目统一 - ✅ 缓存 key 必设过期时间,且加随机偏移防雪崩
- ✅ 更新数据:先更新数据库,再删缓存
- ✅ 写代码时用连接池(主流客户端默认就有)
- ✅ 需要"判断+修改"的原子操作用 Lua
- ❌ 不要把 Redis 当成主数据库存唯一数据(除非你非常清楚持久化的边界)
- ❌ 不要在 Redis 里存能从数据库轻易查到、又几乎不访问的冷数据
7. 监控什么指标(了解)
用 info 命令能看到的关键指标:
| 指标 | 含义 | 警戒 |
|---|---|---|
used_memory / maxmemory | 内存使用率 | > 80% 要扩容或清理 |
keyspace_hits / (hits+misses) | 缓存命中率 | < 90% 说明缓存设计有问题 |
connected_clients | 连接数 | 突增可能是连接泄漏 |
evicted_keys | 被淘汰的 key 数 | 持续增长 = 内存不够 |
rejected_connections | 被拒绝的连接 | > 0 就要查 |
可视化监控常用:RedisInsight(官方 GUI)、Prometheus + Grafana(redis_exporter)。
8. 全教程避坑 TOP 10 回顾
- 生产禁用
keys *,用scan - 不带
EX的set会清掉原有过期时间(想保留用keepttl) - 缓存 key 都要设过期时间,过期时间加随机数
- Redis 事务运行时错误不回滚,原子逻辑用 Lua
- List 当队列没有 ack,可靠场景用 Stream
zrevrank排名从 0 开始,展示记得 +1- 分布式锁:
SET NX EX+ 随机 token + Lua 释放,三者缺一不可 - 大 key 拆分,删除用
unlink - 批量写用 Pipeline
- 公网 Redis 必须设密码 + bind 内网
进阶篇完结!最后是随时翻阅的附录 👉 01 常用命令速查表