Java 中 Redis 过期策略深度解析(含拓展-redis内存淘汰策略列举)

06-01 1229阅读

🤟致敬读者

  • 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉

    📘博主相关

    • 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息

      文章目录

          • Java 中 Redis 过期策略深度解析
            • 一、Redis 过期策略核心原理回顾
            • 二、Java 中的过期操作 API
              • 1. Jedis 客户端操作
              • 2. Spring Data Redis 操作
              • 三、Java 中的策略实践要点
                • 1. 过期时间设置策略
                • 2. 大Key过期优化
                • 3. 缓存穿透/击穿防护
                • 四、生产环境最佳实践
                  • 1. 过期键监控
                  • 2. 动态调整策略
                  • 3. 集群环境注意事项
                  • 五、常见问题排查
                    • 1. 内存未释放问题
                    • 2. 过期键未删除问题
                    • 六、高级特性应用
                      • 1. Redisson 过期监听
                      • 2. RedisJSON 过期扩展
                      • 总结:Java 开发者必备技能
                      • 拓展(Redis内存淘汰策略列举)
                        • noeviction 默认的
                        • volatile-lru
                        • volatile-ttl
                        • volatile-random
                        • allkeys-lru
                        • allkeys-random

                          📃文章前言

                          • 🔷文章均为学习工作中整理的笔记。
                          • 🔶如有错误请指正,共同学习进步。

                            Java 中 Redis 过期策略深度解析

                            在 Java 应用中,Redis 的过期策略是缓存管理的核心机制,直接关系到内存使用效率和系统性能。下面从原理到实践全面解析:


                            一、Redis 过期策略核心原理回顾
                            1. 双重删除策略:

                              • 惰性删除:访问时检查过期时间,若过期则立即删除
                              • 定期删除:Redis 每秒执行 10 次(可配置)的过期扫描
                                # redis.conf 配置
                                hz 10  # 每秒扫描频率
                                
                              • 内存淘汰机制:


                            二、Java 中的过期操作 API
                            1. Jedis 客户端操作
                            // 设置键值对并指定过期时间(秒)
                            jedis.setex("user:session:1001", 1800, "session_data"); 
                            // 单独设置过期时间
                            jedis.expire("cache:product:2023", 3600);  // 秒
                            jedis.pexpire("temp:data", 5000L);         // 毫秒
                            // 获取剩余时间
                            long ttl = jedis.ttl("user:session:1001"); // 秒
                            long pttl = jedis.pttl("cache:product:2023"); // 毫秒
                            
                            2. Spring Data Redis 操作
                            // 注解方式设置缓存过期
                            @Cacheable(value = "users", key = "#userId", 
                                       cacheManager = "customCacheManager")
                            public User getUser(String userId) {
                                // ...
                            }
                            // 配置自定义 CacheManager
                            @Bean
                            public RedisCacheManager customCacheManager(RedisConnectionFactory factory) {
                                RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                                    .entryTtl(Duration.ofMinutes(30)) // 全局默认30分钟
                                    .serializeValuesWith(SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer(User.class)));
                                
                                return RedisCacheManager.builder(factory)
                                       .cacheDefaults(config)
                                       .withCacheConfiguration("users", 
                                            RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(2))) // 特定缓存2小时
                                       .build();
                            }
                            

                            三、Java 中的策略实践要点
                            1. 过期时间设置策略
                            • 动态 TTL:避免缓存雪崩

                              // 基础过期时间 + 随机偏移量
                              int baseExpire = 3600; // 1小时
                              int randomOffset = new Random().nextInt(600); // 0-10分钟随机
                              jedis.setex("hot_product", baseExpire + randomOffset, productData);
                              
                            • 分级过期:

                              数据类型建议 TTL说明
                              用户会话30-60分钟高安全性要求
                              商品详情2-4小时中等更新频率
                              全局配置永久(不设)极少变更
                              2. 大Key过期优化

                              Redis 6.0+ 异步删除配置:

                              // 启动Redis时配置异步删除
                              new RedisServer("redis-server", 
                                  "--lazyfree-lazy-expire yes",
                                  "--lazyfree-lazy-eviction yes");
                                  
                              // Redisson 处理大Hash
                              RMapCache map = redisson.getMapCache("products");
                              map.expire(2, TimeUnit.HOURS); // 整个Map过期
                              
                              3. 缓存穿透/击穿防护
                              // 双重检查锁解决缓存击穿
                              public Product getProduct(String id) {
                                  String key = "product:" + id;
                                  String data = jedis.get(key);
                                  
                                  if ("".equals(data)) return null; // 空值缓存
                                  
                                  if (data == null) {
                                      synchronized (this) {
                                          data = jedis.get(key);
                                          if (data == null) {
                                              Product product = db.getProduct(id);
                                              if (product == null) {
                                                  jedis.setex(key, 300, ""); // 空值缓存5分钟
                                                  return null;
                                              }
                                              jedis.setex(key, 3600, serialize(product));
                                              return product;
                                          }
                                      }
                                  }
                                  return deserialize(data);
                              }
                              

                              四、生产环境最佳实践
                              1. 过期键监控
                              // 获取Redis统计信息
                              String stats = jedis.info("stats");
                              Pattern pattern = Pattern.compile("expired_keys:(\\d+)");
                              Matcher matcher = pattern.matcher(stats);
                              if (matcher.find()) {
                                  long expiredKeys = Long.parseLong(matcher.group(1));
                                  metrics.record("redis.expired_keys", expiredKeys);
                              }
                              // Spring Boot Actuator 监控
                              @Bean
                              public MeterRegistryCustomizer redisMetrics() {
                                  return registry -> {
                                      registry.gauge("redis.expired_keys", 
                                          Tags.of("host", redisHost),
                                          () -> jedis.info("stats").contains("expired_keys:") ? 
                                                 Long.parseLong(jedis.info("stats").split("expired_keys:")[1].split("\r")[0]) : 0
                                      );
                                  };
                              }
                              
                              2. 动态调整策略
                              // 根据负载动态调整过期时间
                              int getDynamicTTL() {
                                  double load = getSystemLoad();
                                  if (load > 0.8) return 600;   // 高负载时缩短TTL
                                  if (load  
                              
                              3. 集群环境注意事项
                              • 主从延迟:主节点删除后从节点可能短暂存在过期数据
                                // 强制读主节点解决脏读
                                if (consistencyRequired) {
                                    jedis.readonly(); // 关闭只读模式(默认从主节点读)
                                }
                                
                              • 跨数据中心:使用 Redisson 的 RRemoteService
                                RRemoteService remoteService = redisson.getRemoteService();
                                remoteService.register(ProductService.class, productServiceImpl, 
                                    RemoteInvocationOptions.defaults().timeout(3, TimeUnit.SECONDS));
                                

                                五、常见问题排查
                                1. 内存未释放问题

                                现象:INFO memory 显示内存未减少

                                排查步骤:

                                1. 检查 maxmemory-policy 配置
                                2. 监控 evicted_keys 和 expired_keys 计数器
                                3. 使用 redis-cli --bigkeys 分析大Key
                                4. 检查是否启用异步删除(Redis 6.0+)
                                2. 过期键未删除问题

                                原因:

                                • 键长期未被访问(惰性删除未触发)
                                • 定期删除扫描未命中(概率性遗漏)
                                • 主从同步延迟

                                  解决方案:

                                  // 主动触发过期扫描(生产慎用)
                                  jedis.configSet("hz", 100);  // 临时提高扫描频率
                                  Thread.sleep(5000);          // 等待5秒
                                  jedis.configSet("hz", 10);   // 恢复默认
                                  

                                  六、高级特性应用
                                  1. Redisson 过期监听
                                  // 监听特定键过期事件
                                  RMapCache map = redisson.getMapCache("sessions");
                                  map.addListener(new ExpiredListener() {
                                      @Override
                                      public void onExpired(EntryEvent event) {
                                          log.info("Session expired: {}", event.getKey());
                                          // 触发清理动作
                                      }
                                  });
                                  
                                  2. RedisJSON 过期扩展
                                  // 使用 RedisJSON 模块设置字段级过期
                                  JSONObject product = new JSONObject();
                                  product.put("id", 1001);
                                  product.put("name", "Laptop");
                                  product.put("price", 999.99);
                                  // 设置整体过期
                                  jedis.jsonSetWithEscape("product:1001", product, 3600);
                                  // 设置字段级过期(需要RedisJSON 2.6+)
                                  jedis.sendCommand(
                                      Command.JSON_SET, 
                                      "product:1001", 
                                      ".price", 
                                      "\"899.99\"", 
                                      "EX", 
                                      "600" // 价格字段10分钟后过期
                                  );
                                  

                                  总结:Java 开发者必备技能

                                  1. 策略选择:

                                    • 会话数据 → volatile-ttl
                                    • 高频访问数据 → volatile-lru
                                    • 全局数据 → allkeys-lru
                                    • 性能口诀:

                                      Java 中 Redis 过期策略深度解析(含拓展-redis内存淘汰策略列举)
                                      (图片来源网络,侵删)

                                      “小Key高频用惰删,大Key过期启异步;

                                      动态TTL防雪崩,双删机制保一致”

                                      Java 中 Redis 过期策略深度解析(含拓展-redis内存淘汰策略列举)
                                      (图片来源网络,侵删)
                                    • 监控指标:

                                      指标健康阈值报警条件
                                      expired_keys/sec<1000持续>5000
                                      evicted_keys/sec0任何驱逐发生
                                      mem_fragmentation_ratio1.0-1.5>1.8 或 <0.9

                                  掌握这些知识,你将在 Java 项目中构建高效可靠的 Redis 缓存系统,轻松应对高并发场景下的数据过期挑战。

                                  Java 中 Redis 过期策略深度解析(含拓展-redis内存淘汰策略列举)
                                  (图片来源网络,侵删)


                                  拓展(Redis内存淘汰策略列举)

                                  Redis 提供了几种内存淘汰策略来处理当可用内存不足时如何自动删除键以释放空间的问题。以下是 Redis 中常见的几种内存淘汰策略:

                                  noeviction 默认的

                                  这是默认的策略。当内存使用达到上限并且客户端尝试执行会导致更多内存使用的命令(比如添加新数据)时,Redis 会返回错误。

                                  实现方式:Redis 直接拒绝执行可能导致内存增加的命令。

                                  例子:假设 Redis 已经达到内存上限,此时执行SET命令添加新的键值对,Redis 会返回错误并拒绝该操作。

                                  volatile-lru

                                  从设置了过期时间的键值对中,移除最近最少使用的键值对。

                                  实现方式:Redis 会维护一个记录设置了过期时间的键的访问时间的队列,当需要淘汰数据时,从队列尾部移除元素。

                                  例子:有多个设置了过期时间的键key1、key2和key3,其中key1最近访问最少,当内存不足时,key1会被淘汰。

                                  volatile-ttl

                                  移除即将过期的键值对,也就是剩余生存时间(TTL)最短的键值对。

                                  实现方式:Redis 会遍历设置了过期时间的键,比较它们的 TTL,选择 TTL 最小的进行淘汰。

                                  例子:键keyA的 TTL 为 10 秒,键keyB的 TTL 为 5 秒,当内存不足时,keyB会被优先淘汰。

                                  volatile-random

                                  在设置了过期时间的键值对中,随机移除某个键值对。

                                  实现方式:通过随机算法从设置了过期时间的键集合中选择一个进行淘汰。

                                  例子:在一组设置了过期时间的键中,随机选取一个如keyX进行淘汰。

                                  allkeys-lru

                                  从所有键值对中,移除最近最少使用的键值对。

                                  实现方式:Redis 维护一个所有键的访问时间队列,淘汰时从队列尾部移除。

                                  例子:包括设置了过期时间和未设置过期时间的多个键,如keyC最近访问最少,当内存不足时,keyC被淘汰。

                                  allkeys-random

                                  从所有键值对中,随机移除某个键值对。

                                  实现方式:通过随机算法从所有键集合中选择一个进行淘汰。

                                  例子:在所有键中,随机选择如keyY进行淘汰。

                                  该拓展部分参考文章:https://cloud.tencent.com/developer/news/1677151


                                  📜文末寄语

                                  • 🟠关注我,获取更多内容。
                                  • 🟡技术动态、实战教程、问题解决方案等内容持续更新中。
                                  • 🟢《全栈知识库》技术交流和分享社区,集结全栈各领域开发者,期待你的加入。
                                  • 🔵​加入开发者的《专属社群》,分享交流,技术之路不再孤独,一起变强。
                                  • 🟣点击下方名片获取更多内容🍭🍭🍭👇
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码