必须显式配置连接池,否则高频访问下易触发文件描述符耗尽、连接拒绝或假死;需设max_connections为并发量1.5–2倍、启用socket_keepalive、禁用decode_responses、避免json/pickle序列化、规范键名并强制ttl、拦截穿透/击穿。

直接用 redis-py 默认连接方式在高频场景下大概率会出问题:连接耗尽、序列化拖慢、键冲突、缓存雪崩——不是缓存没起作用,而是用法本身就在制造瓶颈。
连接池必须显式配置,不能靠默认
高频访问时,每次 redis.Redis() 新建连接会快速打满系统文件描述符,报错 ConnectionRefusedError 或 OSError: Too many open files。默认客户端不带连接池,max_connections 实际为 None,等于放任自流。
- 必须手动初始化
redis.ConnectionPool,并传入connection_pool=pool -
max_connections建议设为应用并发量的 1.5–2 倍(如 uvicorn workers=4 × concurrency=10 → 设 60–80) - 务必开启
socket_keepalive=True,避免中间网络设备断连导致连接假死 - 禁用
decode_responses=True(尤其存二进制数据时),否则msgpack或pickle数据会被错误解码成乱码
别用 json.dumps 存复杂对象
高频写入时,json 序列化是明显性能热点:体积大、编码慢、不支持 datetime / bytes 等原生类型。线上实测,10KB 对象用 json 比 msgpack 慢 3–5 倍,内存占用高 40%。
- 优先选
msgpack.packb(obj, default=str)+msgpack.unpackb(data),兼容性好、速度快、体积小 - 绝对避免
pickle上生产环境——反序列化任意字节流等于开放远程代码执行入口 - 简单字符串或数字,直接用原生类型写入,跳过序列化(如计数器用
incr,不用set+json)
键名设计要带业务上下文和 TTL 控制
键冲突和永不过期是缓存内存泄漏的两大主因。见过太多服务因 user_profile_123 这类裸键,被不同模块反复覆盖,或长期堆积占满 Redis 内存。
- 强制采用三级命名:
cache:{domain}:{type}:{id}(如cache:user:profile:1001) - 所有写操作必须带
ex(秒)或px(毫秒)参数,禁止用set不设过期 - 对强时效数据(如验证码),TTL 必须精确到秒级;对弱时效数据(如用户基础资料),可用
ex=3600配合主动刷新逻辑 - 慎用通配符
keys cache:user:*—— 高频调用会阻塞 Redis 单线程,改用scan渐进清理
缓存穿透/击穿必须在客户端拦截
Redis 本身不解决穿透问题。当大量请求查不存在的 user:9999999,会全部打到数据库,瞬间压垮后端。这不是 Redis 的锅,是客户端没兜底。
- 对空结果也缓存,但 TTL 缩短(如
ex=60),避免长期污染 - 使用布隆过滤器(
pybloom_live)前置校验 ID 是否可能有效,无效请求直接返回 - 热点 key 击穿(如
cache:article:top10过期瞬间涌进上千请求),用setnx+ 过期时间实现“逻辑锁”,只放行一个请求回源加载 - 装饰器里别只判
get是否为空——要区分None(未命中)、b''(空缓存)、实际数据三种状态
真正卡住人的从来不是“怎么把数据塞进 Redis”,而是连接怎么不炸、序列化怎么不拖、键怎么不撞、空请求怎么不漏——这些细节没对齐,缓存反而成了性能负资产。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











