
你用上了Redis,数据库压力下来了,网站快了一些。但你看了眼监控,命中率只有30%。100次查询,70次穿透到数据库。Redis像个摆设。
你开始怀疑:是不是Redis没用对?是不是该换更大的内存?
别急。命中率低通常不是硬件问题,是策略问题。今天聊怎么把命中率从30%拉到90%。
先看一个数据
某电商网站,商品详情页用了Redis缓存,命中率只有35%。分析后发现,缓存过期时间设了1小时,但热门商品每秒被访问几百次,过期后第一批请求全部穿透到数据库。
把热门商品过期时间从1小时延长到24小时,命中率从35%升到78%。不升级硬件,只改了个数字。
命中率低的核心原因不是内存小,是你不知道哪些数据值得缓存、缓存多久、怎么更新。
命中率低的原因排查
排查命中率问题,先看监控:
bash
# Redis INFO命令查看命中率 redis-cli INFO stats | grep keyspace
输出keyspace_hits和keyspace_misses。命中率 = hits / (hits + misses)。
命中率低于50%,说明大量请求没命中缓存,直接查了数据库。
策略一:只缓存热数据
你以为把整个数据库塞进Redis,命中率就高了。内存爆炸,冷数据占着空间,热数据被挤出去。
缓存不是数据库。只存高频访问的热数据。
找热数据的方法:在业务代码里埋点,统计每个key的访问频率。或分析慢查询日志,看哪些查询最频繁。或预估:商品详情页、用户会话、配置信息,大概率是热数据。
热数据通常符合二八原则:20%的数据贡献80%的访问。把精力放在那20%上。
策略二:合理设置过期时间(TTL)
过期时间太短,数据频繁失效,命中率低。过期时间太长,数据更新不及时,用户看到旧内容。
按数据类型分策略:
| 数据类型 | 特点 | 建议TTL |
|---|---|---|
| 热门商品详情 | 访问极高、变化少 | 24小时+主动更新 |
| 用户会话 | 访问高、变化少 | 30分钟(随活动续期) |
| 配置信息 | 访问高、极少变 | 永久+手动刷新 |
| 排行榜 | 访问高、定期变 | 5-10分钟 |
| 计数类(点赞数) | 访问极高、实时变 | 不设过期,靠更新维护 |
主动更新是指在数据变更时,实时更新缓存,不是等它过期。用DEL或SET在数据库更新后同步刷新。
策略三:解决缓存穿透
缓存穿透:查询一个不存在的数据。缓存没有,数据库也没有。每次请求都穿透到数据库,恶意攻击会压垮数据库。
解决方案:
- 缓存空值:查不到的数据,在Redis里存一个空值,过期时间短(如1分钟)
- 布隆过滤器:把所有存在的key存到布隆过滤器,请求先过过滤器,不存在就直接返回
布隆过滤器准确率高、内存占用小,适合防止恶意穿透攻击。
策略四:解决缓存雪崩
缓存雪崩:大量key在同一时间过期,请求同时穿透到数据库,数据库瞬间压力爆增。
解决方案:
- 过期时间加随机偏移:
EXPIRE key 3600 + random(0,300),避免同一秒集体失效 - 热点数据永不过期:逻辑过期,由后台异步更新
- 多级缓存:本地缓存(Caffeine)+ Redis,本地缓存扛住穿透压力
策略五:解决缓存击穿
缓存击穿:某个热点key过期瞬间,大量请求同时打到数据库。
解决方案:
- 互斥锁:第一个请求去查数据库并重建缓存,其他请求等待
python
# Python伪代码
def get_product(product_id):
data = redis.get(product_id)
if data:
return data
# 尝试获取锁
if redis.setnx("lock:" + product_id, "1"):
data = db.query(product_id)
redis.setex(product_id, 3600, data)
redis.delete("lock:" + product_id)
else:
time.sleep(0.1)
return get_product(product_id)
- 逻辑过期:缓存里存两个字段
value和expire_time,发现逻辑过期后,一个线程去更新,其他线程先返回旧数据
击穿和雪崩的区别:击穿是一个key,雪崩是很多key。
策略六:选择合适的淘汰策略
内存满了,Redis要淘汰一些key。默认是noeviction,不淘汰直接报错。
适合你场景的策略:
- allkeys-lru:最近最少使用,通用。不知道选什么就选这个。
- volatile-lru:只淘汰设了过期时间的key,保留永久key
- allkeys-lfu:最近最不常使用,适合有明显冷热分布的场景
bash
# 查看当前淘汰策略 redis-cli CONFIG GET maxmemory-policy # 设置淘汰策略 redis-cli CONFIG SET maxmemory-policy allkeys-lru
案例:命中率从35%提升到92%
一个新闻网站,用Redis缓存文章详情,命中率长期在35%左右。
第一步:分析访问日志,发现80%的访问集中在最近3天的热门文章。热门标签文章、首页推荐文章访问量是普通文章的50倍。
第二步:调整策略:
- 热门文章TTL从1小时改成24小时
- 普通文章TTL保持1小时
- 冷门文章不缓存(访问少,缓存意义不大)
第三步:加布隆过滤器,防止恶意爬虫穿透。
一周后,命中率从35%升到86%。进一步优化:
- 热门文章永不过期,有更新时主动刷新缓存
- 首页聚合数据独立缓存,不再由各篇文章独立缓存
最终命中率稳定在92%。
监控和调优
持续监控命中率趋势,设置告警。工具:
- Redis内置命令:
redis-cli INFO stats - Prometheus + Grafana:展示命中率曲线
- RedisInsight:可视化分析
调优方向:
- 命中率下降 → 检查最近是否改了缓存策略、TTL是否合理
- 内存使用率 > 80% → 检查淘汰策略是否生效、是否有大key
- 某个key miss率异常高 → 单独分析该key
最后一句
命中率不是越高越好。100%命中意味着数据从不更新,对很多业务不现实。90%左右是一个健康的区间。
与其抱怨命中率低,不如去分析一下:哪些数据在穿透?为什么穿透?热数据你缓存了吗?过期时间合理吗?
从30%到90%,不需要换硬件,只需要换策略。今天去改你的redis.conf,调整淘汰策略,给热点数据更长的生命。




