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

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

🤟致敬读者

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

📘博主相关

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

文章目录

      • 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  # 每秒扫描频率
      
  2. 内存淘汰机制

    内存达到 maxmemory
    淘汰策略
    volatile-lru
    volatile-ttl
    volatile-random
    allkeys-lru
    noeviction

二、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<String, Product> 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<MeterRegistry> 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;   // 高负载时缩短TTLif (load < 0.3) return 3600;  // 低负载时延长TTLreturn 1800;                  // 默认30分钟
}jedis.setex("cache:data", getDynamicTTL(), data);
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_keysexpired_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<String, String> map = redisson.getMapCache("sessions");
map.addListener(new ExpiredListener<String, String>() {@Overridepublic void onExpired(EntryEvent<String, String> 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
  2. 性能口诀

    “小Key高频用惰删,大Key过期启异步;
    动态TTL防雪崩,双删机制保一致”

  3. 监控指标

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

掌握这些知识,你将在 Java 项目中构建高效可靠的 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


📜文末寄语

  • 🟠关注我,获取更多内容。
  • 🟡技术动态、实战教程、问题解决方案等内容持续更新中。
  • 🟢《全栈知识库》技术交流和分享社区,集结全栈各领域开发者,期待你的加入。
  • 🔵​加入开发者的《专属社群》,分享交流,技术之路不再孤独,一起变强。
  • 🟣点击下方名片获取更多内容🍭🍭🍭👇

相关文章:

  • spring boot项目中的一些常用提示信息
  • C++17新特性 Lambda表达式
  • 第十四篇:MySQL 运维中的故障场景还原与排查实战技巧
  • NLP基础:从词嵌入到预训练模型应用
  • token
  • 进程间通信(消息队列)
  • C++学习打卡
  • qwen3解读
  • Redis事务详解:原理、使用与注意事项
  • vue-09(使用自定义事件和作用域插槽构建可重用组件)
  • 磨皮功能 C++/C的OpenCV 实现
  • 【11408学习记录】考研英语写作提分秘籍:2013真题邀请信精讲+万能模板套用技巧
  • 【shell】通过Shell命令占用内存
  • 利用python工具you-get下载网页的视频文件
  • #AI短视频制作完整教程
  • JDK21深度解密 Day 9:响应式编程模型重构
  • CTFHub-RCE 命令注入-过滤目录分隔符
  • 小明的Java面试奇遇之互联网保险系统架构与性能优化
  • 性能优化 - 理论篇:CPU、内存、I/O诊断手段
  • Unity3D仿星露谷物语开发57之保存库存信息到文件
  • 如何开发小程序?/seo关键词优化排名软件
  • 外国男男做暧暧视频网站/建立网站一般要多少钱
  • 如何提高网站响应速度/sem代运营公司
  • 做网站玩玩/站长之家是干什么的
  • 自己做的网站服务器在哪里/怎么设计网站
  • 动态网站建设与维护/班级优化大师的优点