架构师成长之路|Redis key过期清除策略

本文详细介绍了Redis的缓存清除策略,包括noeviction、LRU、LFU、TTL等多种策略的使用场景和推荐。文章讨论了Redis的近似LRU算法及其改进,并提到了Redis 4.0引入的LFU模式,该模式在某些情况下能提供更好的命中率。

Eviction policies

maxmemory 100mb

当我们设置的内存达到指定的内存量时,清除策略的配置方式决定了默认行为。Redis可以为可能导致使用更多内存的命令返回错误,也可以在每次添加新数据时清除一些旧数据以返回到指定的限制。

当达到最大内存限制时,Redis所遵循的确切行为是使用MaxMemory-Policy配置指令配置的。

Redis的清除策略有以下:

  • noeviction:当达到内存限制时,不保存新值。当数据库使用replicate时,这适用于主数据库
  • allkeys-lru :保留最近使用的key;删除最近最少使用的(LRU)keys
  • allkeys-lfu : 保留经常使用的key;删除不常使用的(LFU)keys
  • volatile-lru: 删除过期字段设置为True的最近最少使用的keys
  • volatile-lfu: 删除过期字段设置为True的最近最不常使用的keys
  • allkeys-random: 随机删除keys,为添加的新数据腾出空间。
  • volatile-random: 随机删除过期字段设置为TRUE的keys。
<think>我们正在构建一个基于Spring Boot 3的分层架构,整合Quartz(用于定时任务调度)Redis(用于缓存分布式锁)。架构将遵循标准的分层设计:控制器层(Controller)、服务层(Service)、数据访问层(Repository)实体层(Entity)。同时,我们将考虑分布式环境中Quartz的配置Redis的应用。 ### 1. 项目初始化与依赖管理 使用Spring Initializr(https://start.spring.io/)初始化项目,选择以下依赖: - Spring Web - Spring Data JPA - Spring Data Redis - Quartz Scheduler - Lombok(简化代码) Maven依赖示例(pom.xml): ```xml <dependencies> <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- Spring Data Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- Quartz --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- 数据库驱动(以MySQL为例) --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> </dependencies> ``` ### 2. 分层架构设计 项目结构示例: ``` src/main/java/com/example/demo ├── config // 配置类 ├── controller // 控制器层 ├── entity // 实体类 ├── repository // 数据访问层(JPA Repository) ├── service // 服务层(接口与实现分离) │ ├── impl └── task // 定时任务相关(Job定义配置) ``` ### 3. 整合Redis #### 3.1 配置Redis 在`application.properties`中配置Redis连接: ```properties # Redis配置 spring.redis.host=localhost spring.redis.port=6379 spring.redis.password= spring.redis.database=0 ``` #### 3.2 使用RedisTemplate或缓存注解 - **RedisTemplate**:用于直接操作Redis,适合复杂操作。 - **Spring Cache抽象**:使用`@Cacheable`、`@CachePut`等注解简化缓存。 配置缓存管理器(可选): ```java @Configuration @EnableCaching public class RedisCacheConfig { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { return RedisCacheManager.builder(connectionFactory) .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10))) // 默认缓存过期时间 .build(); } } ``` 在Service层使用缓存: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Override @Cacheable(value = "userCache", key = "#id") public User getUserById(Long id) { return userRepository.findById(id).orElse(null); } } ``` ### 4. 整合Quartz #### 4.1 配置Quartz 在`application.properties`中配置Quartz(这里使用内存存储,适合非持久化任务): ```properties # Quartz配置(内存存储) spring.quartz.job-store-type=memory ``` 对于分布式环境,需要数据库存储(JDBC JobStore)并配置数据源。但注意:如果配置了数据源,Quartz会使用数据库存储任务信息[^3]。为了避免干扰,我们先使用内存存储。 #### 4.2 创建Job类 使用Spring管理Job,可以通过依赖注入使用ServiceRedisTemplate: ```java @Component public class SampleJob extends QuartzJobBean { @Autowired private UserService userService; @Autowired private RedisTemplate<String, String> redisTemplate; @Override protected void executeInternal(JobExecutionContext context) { // 使用Redis分布式锁确保集群中只有一个实例执行 String lockKey = "jobLock"; boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", Duration.ofSeconds(30)); if (locked) { try { // 执行业务逻辑 userService.cleanExpiredUsers(); } finally { redisTemplate.delete(lockKey); } } else { // 获取锁失败,说明其他节点正在执行 } } } ``` #### 4.3 配置JobDetailTrigger 使用`QuartzConfig`配置定时任务: ```java @Configuration public class QuartzConfig { @Bean public JobDetail sampleJobDetail() { return JobBuilder.newJob(SampleJob.class) .withIdentity("sampleJob") .storeDurably() .build(); } @Bean public Trigger sampleJobTrigger() { return TriggerBuilder.newTrigger() .forJob(sampleJobDetail()) .withIdentity("sampleTrigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/5 * * * ?")) // 每5分钟执行一次 .build(); } } ``` ### 5. 分布式环境下的优化 - **Quartz集群**:如果需要高可用持久化,配置JDBC JobStore并共享数据库[^1]。 - **Redis分布式锁**:确保在集群环境中定时任务只有一个节点执行(如上例所示)。 - **Redis缓存优化**:根据业务需求调整缓存策略过期时间、淘汰策略等)。 ### 6. 完整示例代码 #### 实体类(Entity) ```java @Entity @Data public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; } ``` #### Repository接口 ```java public interface UserRepository extends JpaRepository<User, Long> { // 自定义查询方法 @Modifying @Query("delete from User u where u.lastLogin < :expireDate") void deleteExpiredUsers(@Param("expireDate") LocalDateTime expireDate); } ``` #### Service层 ```java public interface UserService { User getUserById(Long id); void cleanExpiredUsers(); } @Service public class UserServiceImpl implements UserService { private final UserRepository userRepository; public UserServiceImpl(UserRepository userRepository) { this.userRepository = userRepository; } @Override @Transactional public void cleanExpiredUsers() { LocalDateTime expireDate = LocalDateTime.now().minusDays(30); userRepository.deleteExpiredUsers(expireDate); } @Override public User getUserById(Long id) { return userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found")); } } ``` #### Controller层 ```java @RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { return ResponseEntity.ok(userService.getUserById(id)); } } ``` ### 7. 配置类主启动类 #### 主启动类 ```java @SpringBootApplication @EnableCaching public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` ### 8. 注意事项 1. **Quartz与数据源**:如果项目中有其他数据源配置,确保Quartz的存储类型(`spring.quartz.job-store-type`)明确设置,避免意外使用数据库存储[^3]。 2. **分布式锁超时**:设置合理的锁超时时间,避免任务执行时间过长导致锁提前释放。 3. **事务管理**:在Service层的方法上使用`@Transactional`确保数据一致性。 ### 总结 本架构整合了Spring Boot 3、QuartzRedis,实现了分层设计: - **Controller层**:处理HTTP请求。 - **Service层**:业务逻辑,整合缓存事务。 - **Repository层**:数据库访问。 - **Task层**:定时任务,配合Redis分布式锁确保集群安全。 对于定时任务,我们使用Quartz的内存存储,适合轻量级应用;分布式环境可通过JDBC JobStore实现高可用。Redis作为缓存分布式锁的工具,提升了系统性能可靠性。 §§相关问题§§ 1. 在Spring Boot 3中,如何配置Quartz使用数据库存储(JDBC JobStore)? 2. Redis分布式锁在集群环境下可能遇到哪些问题?如何解决? 3. 如何优化Spring Boot应用中的Redis缓存策略以提高性能? 4. 在分布式定时任务中,除了Redis分布式锁,还有哪些方法确保任务幂等性? </think>以下是基于Spring Boot 3、QuartzRedis的分层架构建议,整合了您提供的引用内容中的关键要点: ### 分层架构设计(Spring Boot 3) ``` src/main/java/com/yourproject ├── config // 配置类 │ ├── RedisConfig.java // Redis配置 │ └── QuartzConfig.java // Quartz配置 ├── controller // 控制器层 │ └── UserController.java ├── entity // 实体类 │ └── User.java ├── repository // 数据访问层 │ └── UserRepository.java ├── service // 服务层 │ ├── UserService.java // 服务接口 │ └── impl/UserServiceImpl.java // 实现类 └── task // 定时任务 ├── job/UserCleanupJob.java // Quartz Job └── scheduler/TaskScheduler.java // 任务调度 ``` --- ### 关键技术整合建议 #### 1. Redis整合(缓存与分布式锁) ```java // Redis配置类 @Configuration @EnableCaching public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } } // 服务层缓存使用 @Service public class UserServiceImpl implements UserService { @Cacheable(value = "users", key = "#id") // 自动缓存 public User getUserById(Long id) { // 数据库查询 } // 分布式锁实现 public void safeOperation() { String lockKey = "resource_lock"; Boolean locked = redisTemplate.opsForValue() .setIfAbsent(lockKey, "locked", 30, TimeUnit.SECONDS); if (Boolean.TRUE.equals(locked)) { try { // 受保护的业务逻辑 } finally { redisTemplate.delete(lockKey); } } } } ``` *最佳实践*: - 使用`@Cacheable`注解简化高频数据缓存[^3] - 分布式锁采用`setIfAbsent`原子操作,避免并发问题[^4] - 为不同数据类型选择合适结构(String/Hash/ZSet)[^3] --- #### 2. Quartz定时任务(分布式支持) ```java // Quartz配置 @Configuration public class QuartzConfig { @Bean public JobDetail userCleanupJobDetail() { return JobBuilder.newJob(UserCleanupJob.class) .withIdentity("userCleanupJob") .storeDurably() .build(); } @Bean public Trigger userCleanupTrigger() { return TriggerBuilder.newTrigger() .forJob(userCleanupJobDetail()) .withSchedule(CronScheduleBuilder.cronSchedule("0 0 2 * * ?")) // 每天2点执行 .build(); } } // 定时任务实现(集成Redis锁) public class UserCleanupJob implements Job { @Autowired private UserService userService; @Override public void execute(JobExecutionContext context) { userService.cleanExpiredUsers(); // 调用服务层方法 } } ``` *关键配置*: ```properties # application.properties spring.quartz.job-store-type=jdbc # 集群使用数据库存储[^1] spring.quartz.properties.org.quartz.jobStore.isClustered=true ``` *最佳实践*: - 复杂调度场景优先选择Quartz[^2] - 集群环境启用JDBC存储保证任务一致性[^1] - 任务逻辑委托给Service层保持单一职责 --- #### 3. 分层调用流程 ```mermaid graph TD A[Controller] -->|HTTP请求| B(Service) B -->|业务逻辑| C[Repository] C -->|JPA操作| D[(Database)] B -->|缓存读写| E[(Redis)] F[Quartz Job] -->|调用| B B -->|分布式锁| E ``` --- ### 架构优化建议 1. **定时任务选型策略**: - 简单延迟任务:Redis ZSet(订单超时)[^2] - 复杂调度:Quartz + DB(财务对账)[^2] - 高频任务:时间轮算法(缓存刷新) 2. **分布式锁加强**: ```java // Redisson分布式锁(推荐) RLock lock = redissonClient.getLock("resourceLock"); try { if(lock.tryLock(10, 30, TimeUnit.SECONDS)) { // 临界区操作 } } finally { lock.unlock(); } ``` 3. **缓存策略优化**: - 热点数据:永久缓存+主动更新 - 查询结果:`@Cacheable` + TTL - 批量操作:Pipeline管道处理 --- ### 典型配置示例 ```properties # application.properties # Redis spring.data.redis.host=127.0.0.1 spring.cache.redis.time-to-live=3600000 # Quartz集群 spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ ``` --- ### 注意事项 1. **Quartz集群陷阱**: 启用JDBC存储时需同步配置`spring.quartz.properties.org.quartz.scheduler.instanceId`确保节点唯一性[^1] 2. **缓存一致性**: 更新操作需同步清除缓存,推荐使用`@CacheEvict` 3. **任务幂等性**: 所有定时任务需设计幂等逻辑,防止重复执行 4. **Redis序列化**: 使用Jackson替代JDK序列化避免跨平台问题 此架构在电商、金融等领域有成熟应用,能支撑高并发场景下的定时任务调度数据一致性要求[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员路同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值