当前位置: 首页 > news >正文

redis 缓存命中率降低,该如何解决?

命中率降低

Redis 缓存命中率降低,可能是由于多个因素导致的,比如缓存未命中、缓存污染、缓存淘汰过快等。针对不同情况,可以采取以下优化措施:

1. 分析缓存命中率下降的原因

在优化之前,先使用 Redis 监控工具 分析命中率下降的具体原因:

redis-cli info stats | grep "keyspace_hits\|keyspace_misses"
  • keyspace_hits 表示缓存命中次数
  • keyspace_misses 表示缓存未命中次数
  • 计算缓存命中率
    在这里插入图片描述

2. 减少缓存穿透

问题:请求的 Key 在缓存和数据库中都不存在,导致每次请求都要查询数据库,增加 keyspace_misses

解决方案

  • 布隆过滤器(Bloom Filter)
    在 Redis 之前使用 布隆过滤器 存储可能存在的 Key,避免无效查询:
    import com.google.common.hash.BloomFilter;
    import com.google.common.hash.Funnels;
    
    BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 100000);
    bloomFilter.put(12345); // 预存 Key
    if (!bloomFilter.mightContain(54321)) {
        return "数据不存在"; // 直接返回,避免数据库查询
    }
    
  • 缓存空值
    例如,对于查询不到的 Key 存入一个短 TTL(如 60s)的空值:
    SET key "null" EX 60
    
    风险:要避免缓存大量空值,占用 Redis 内存。

3. 减少缓存击穿

问题:某个热点 Key 失效后,短时间内大量请求击中数据库,导致 Redis 负载降低,数据库压力激增。

解决方案

  • 设置热点 Key 的自动续期(使用 逻辑过期+异步重建
    String value = redis.get("hot_key");
    if (value == null) {
        if (redis.setNx("lock_hot_key", "1", 10)) { // 尝试获取锁
            value = dbQuery(); // 查询数据库
            redis.setEx("hot_key", value, 60); // 重新缓存
            redis.del("lock_hot_key"); // 释放锁
        } else {
            Thread.sleep(100); // 等待其他线程加载完成
            value = redis.get("hot_key");
        }
    }
    
  • 预加载数据
    • 提前加载热点数据到 Redis,避免突然失效带来的冲击。
    • 使用 Lua 脚本 实现 原子性 续期:
      local ttl = redis.call("TTL", KEYS[1])
      if ttl > 0 then
          redis.call("EXPIRE", KEYS[1], ttl + 30) -- 续期 30s
      end
      

4. 减少缓存雪崩

问题:大量 Key 同时过期,导致 Redis 负载骤降,数据库压力激增。

解决方案

  • 设置随机过期时间,避免同一时刻大量 Key 失效:
    redis.setEx("key", value, 60 + new Random().nextInt(30)); // 60-90s 随机过期
    
  • 分批加载缓存
    • 在高并发场景下,采用 预热缓存 的方式,在系统启动或数据更新时提前加载缓存。

5. 优化缓存淘汰策略

问题:Redis 可能因为 内存不足 频繁淘汰数据,导致缓存命中率下降。

解决方案

  • 调整淘汰策略
    • volatile-lru淘汰最近最少使用的 key
    • allkeys-lru淘汰所有 key 中最近最少使用的
    • volatile-ttl优先淘汰快过期的 key
    • allkeys-random随机淘汰
    • 设置适合的 maxmemory-policy
      CONFIG SET maxmemory-policy allkeys-lru
      
  • 使用大 Key 拆分
    • 如果某个 Key 过大(如存储了整个用户历史数据),可拆分成多个小 Key,减少单 Key 失效影响。

6. 提升 Redis 读取性能

问题:如果 Redis 本身读取性能下降,也可能导致命中率降低。

解决方案

  • 优化数据结构
    • 使用 Hash 代替 String
      redis.hset("user:1001", "name", "Alice");
      redis.hset("user:1001", "age", "25");
      
    • 减少大 Key 读取,如 List, Set, Zset,避免一次性加载大量数据。
  • 开启 Redis 读写分离
    • 部署 Redis 主从架构,让从节点分担读取压力:
      redis-cli -h master-ip replicaof slave-ip 6379
      
    • 在 Spring Boot 代码中配置多个 Redis 连接:
      spring:
        redis:
          cluster:
            nodes: 192.168.1.1:6379,192.168.1.2:6379,192.168.1.3:6379
      

总结

问题优化方案
缓存穿透布隆过滤器、缓存空值
缓存击穿热点数据续期、逻辑过期、预加载
缓存雪崩随机过期时间、分批加载
缓存淘汰调整淘汰策略、拆分大 Key
Redis 读写读写分离、优化数据结构

Redis 命中率下降的根本原因在于 缓存未命中次数增加缓存数据被频繁淘汰,针对不同的情况,可以结合 预防 + 限流 + 监控 + 读写分离 等手段优化。

如果你的 Redis 缓存命中率持续降低,可以具体分析 请求 Key 的访问分布、数据更新频率、查询模式,再针对性优化。🚀

穿透、击穿、雪崩

缓存穿透:请求一个不存在的数据,导致请求直接到达数据库。
解决方案:对空值缓存,使用布隆过滤器,拦截不存在的请求,避免数据库查询。

缓存击穿:在高并发下,某个数据的缓存失效,导致大量请求同时访问数据库。
解决方案:对热点数据加锁(分布式锁),或使用互斥锁(分布式锁),确保在缓存更新时只允许一个请求访问数据库。

缓存雪崩:大量缓存同时过期,导致瞬间大量请求涌向数据库。
解决方案:设置不同的过期时间,随机化缓存的过期时间,避免集中失效。

相关文章:

  • OMNIWeb 数据介绍
  • uniapp用法--uni.navigateTo 使用与参数携带的方式示例(包含复杂类型参数)
  • 合合信息大模型加速器2.0实测:当AI开始“读心术“与“考古“
  • 若依框架二次开发——若依(RuoYi)实现手机号/邮箱/用户名多方式登录
  • 【MySQL基础-18】MySQL字符函数详解:高效处理文本数据的利器
  • 说说Redis的内存淘汰策略?
  • 课程6. 决策树
  • #不同版本下,单元测试的注解使用
  • Mysql从入门到精通day5————子查询精讲
  • 人工智能的未来:从弱 AI 到通用人工智能(AGI)
  • 常用的卷积神经网络及Pytorch示例实现
  • AI+制造的破局之战(上):从技术爆发到价值穿透,谁将率先定义“智能体时代”?
  • 网络架构搭建中的 QinQ 与端口安全策略
  • python采集淘宝拍立淘按图搜索API接口,json数据示例参考
  • Java中用Stream流取出分组后每组中最大值对应的对象
  • ubuntu开启黑屏现象解决
  • Linux上位机开发实践(从MPP平台到产品)
  • AI大模型从0到1记录学习 day10
  • SvelteKit 最新中文文档教程(16)—— Service workers
  • 【Unity】记录TMPro使用过程踩的一些坑
  • 怎么看网站是谁家做的/免费com域名注册网站
  • 泰安网络推广公司怎么样/企业seo关键字优化
  • 建站报价/成都百度seo推广
  • 网站建设海报/长沙官网优化公司
  • 建设一个网站最低消费/网店推广平台
  • 传奇做网站空间/在线网站建设平台