복붙노트

[SPRING] 봄 데이터 Redis 만료 키

SPRING

봄 데이터 Redis 만료 키

나는 하나의 Spring Hibernate Application을 가지고있다. 내 응용 프로그램에서는 최근 스프링 데이터 Redis 구현됩니다.

spring-servlet.xml
<!-- redis connection factory -->
<bean id="jedisConnFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true"/>

<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" 
    p:connection-factory-ref="jedisConnFactory"/>

그리고이 RedisTemplate은 ServiceImpl 클래스에서 사용됩니다.

RedisServiceImpl

@Autowired
private RedisTemplate<String, T> redisTemplate;

public RedisTemplate<String, T> getRedisTemplate() {
    return redisTemplate;
}

public void setRedisTemplate(RedisTemplate<String, T> redisTemplate) {
    this.redisTemplate = redisTemplate;
}

이제 redisServer에 데이터를 추가했습니다.

public void putData(String uniqueKey, String key, Object results) {

    redisTemplate.opsForHash().put(uniqueKey, key, results);
}

이제 Expire 키를 제거하고 싶습니다.

나는 구글에서 검색하지만, 구글에서 모두 이런 말을하고있다.

redisTemplate.expire(key, timeout, TimeUnit);

이 만료 메서드에서는 key 대신 uniqueKey를 제공해야합니다. 하지만 uniqueKey 대신 Expire 키가 필요합니다.

그래서 만료 키를 위해 무엇을 도와 주시겠습니까?

해결법

  1. ==============================

    1.Redis 버전 3.2.100을 사용하고 있습니다.

    Redis 버전 3.2.100을 사용하고 있습니다.

    redis 템플릿 대신 Use Redis Cache Manager를 사용하고 redistemplate를 cacheManager에 전달하고 set expires 속성을 사용하여 기본적으로 String & Long 맵을 생성합니다. 캐시 이름을 추가하고 만료 시간 (TTL)을 설정할 수 있습니다.

    cacheManager의 setDefaultExpiration 메소드를 사용하여 모든 캐시에 동일한 만료 시간을 설정할 수 있습니다.

    @SuppressWarnings({ "rawtypes", "unused" })
    @Configuration
    @EnableCaching(proxyTargetClass = true, mode = AdviceMode.ASPECTJ, order = 1)
    @PropertySource("classpath:/application.properties")
    public class CacheConfigImpl extends CachingConfigurerSupport {
    
        private @Value("${redis.ip}") String redisHost;
        private @Value("${redis.port}") int redisPort;
    
         private static final Map<String, Long> cacheMap = new HashMap<String, Long>();
        static {
            cacheMap.put("method1cache", 600L);
            cacheMap.put("method2cache", 600L);
            cacheMap.put("method3cache", 800L);
        }
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    
        @Bean
        public JedisConnectionFactory redisConnectionFactory() {
            JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
            redisConnectionFactory.setHostName(CustomPropertyLoader.getProperty("redis.ip"));
            redisConnectionFactory.setPort(Integer.parseInt(CustomPropertyLoader.getProperty("redis.port")));
            return redisConnectionFactory;
        }
    
        @Bean
        public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            redisTemplate.afterPropertiesSet();
            return redisTemplate;
        }
    
        @Bean(name = "RCacheManager")
        public CacheManager cacheManager(RedisTemplate redisTemplate) {
    
            RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
            cacheManager.setExpires(cacheMap);
            cacheManager.setUsePrefix(true);
            final String redis_client_name = CustomPropertyLoader.getProperty("redis.client.name");
            cacheManager.setCachePrefix(new RedisCachePrefix() {
                private final RedisSerializer<String> serializer = new StringRedisSerializer();
                private final String delimiter = ":";
    
                public byte[] prefix(String cacheName) {
                    return this.serializer
                            .serialize(redis_client_name.concat(this.delimiter).concat(cacheName).concat(this.delimiter));
                }
            });
            return cacheManager;
        }
        }
    
  2. ==============================

    2.실제로 RMapCache 객체를 사용하여 Redisson 프레임 워크 (Redis 기반 데이터 격자 for Java)로이 작업을 수행 할 수 있습니다. 맵 엔트리마다 ttl 및 maxIdle을 설정할 수있는 기능을 제공합니다. 예:

    실제로 RMapCache 객체를 사용하여 Redisson 프레임 워크 (Redis 기반 데이터 격자 for Java)로이 작업을 수행 할 수 있습니다. 맵 엔트리마다 ttl 및 maxIdle을 설정할 수있는 기능을 제공합니다. 예:

    // implements java.util.concurrent.ConcurrentMap interface
    RMapCache<String, SomeObject> map = redisson.getMapCache("anyMap");
    
    // ttl = 10 minutes, 
    map.put("key1", new SomeObject(), 10, TimeUnit.MINUTES);
    // ttl = 10 minutes, maxIdleTime = 10 seconds
    map.put("key1", new SomeObject(), 10, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);
    
  3. ==============================

    3.실제로 Redis 해시 내부의 개별 키에 대한 TTL을 만료 시키거나 설정할 수는 없습니다. 전체 해시를 만료 시키거나 TTL로 설정할 수 있습니다. 이를 지원하려면 데이터 구조를 변경해야합니다.

    실제로 Redis 해시 내부의 개별 키에 대한 TTL을 만료 시키거나 설정할 수는 없습니다. 전체 해시를 만료 시키거나 TTL로 설정할 수 있습니다. 이를 지원하려면 데이터 구조를 변경해야합니다.

    왜 이것이 불가능한 지에 대한 링크가 있습니다. 아래는 몇 가지 발췌 내용입니다. 레디스 만료

    또한 해시 필드에서 만료를 설정할 수있는이 링크를 사용하면 데이터 구조를 변경하여 만료를 처리하는 데 도움이 될 수 있습니다.

  4. ==============================

    4.키에 TTL을 설정하려면 cacheManager의 빈을 여러 개 만들고 개별 빈에 대해 TTL을 설정할 수 있습니다. 그런 다음 귀하의 사용에 따라 필요한 cachemanager를 사용할 수 있습니다. 여기 제가 구현 한 것이 있습니다.

    키에 TTL을 설정하려면 cacheManager의 빈을 여러 개 만들고 개별 빈에 대해 TTL을 설정할 수 있습니다. 그런 다음 귀하의 사용에 따라 필요한 cachemanager를 사용할 수 있습니다. 여기 제가 구현 한 것이 있습니다.

    @Configuration("cacheConfig")
    @EnableCaching
    public class CacheConfig extends CachingConfigurerSupport{
    
    
        @Bean
        public JedisConnectionFactory redisConnectionFactory() {
            System.out.println("redisConnectionFactory");
            JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
    
            // Defaults
            redisConnectionFactory.setHostName("127.0.0.1");
            redisConnectionFactory.setPort(6379);
            return redisConnectionFactory;
        }
    
        @Bean
        public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
            System.out.println("redisTemplate");
            RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
            redisTemplate.setConnectionFactory(cf);
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            return redisTemplate;
        }
    
        @Bean
        @Primary
        public CacheManager cacheManager2(RedisTemplate redisTemplate) {
            RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
            // Number of seconds before expiration. Defaults to unlimited (0)
            cacheManager.setDefaultExpiration(20);
            cacheManager.setUsePrefix(true);
            return cacheManager;
        }
    
    
        @Bean
        public CacheManager cacheManager1(RedisTemplate redisTemplate) {
            RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
            // Number of seconds before expiration. Defaults to unlimited (0)
            cacheManager.setDefaultExpiration(60);
            cacheManager.setUsePrefix(true);
            return cacheManager;
        }
    
    }
    

    위에 작성한 cachemanager beans를 사용하려면,

    @Cacheable(value = "users", key = "#userId.toString()", cacheManager ="cacheManager2")
        @RequestMapping(value = "/{userId}", method = RequestMethod.GET)
        public User getUser(@PathVariable String userId) {
            LOG.info("Getting user with ID {}.: "+userId);
          return userService.fetchUserDataonUsers(userId);
        }
    
    
    @Cacheable(value = "users", key = "#userId.toString()", cacheManager ="cacheManager1")
        @RequestMapping(value = "data/{userId}", method = RequestMethod.GET)
        public String getUserData(@PathVariable String userId) {
            LOG.info("Getting user with ID getUserData {}.: "+userId);
          return userService.fetchUserDataonUsers(userId).toString();
        }
    

    우리는 @Cacheable에 cacheManager = "cacheManager2"를 정의 할 때, 구성에 정의 된 cacheManager2에 대해 TTL 세트를 사용합니다. cacheManager1과 동일합니다.

  5. ==============================

    5.이러한 목적으로 Quartz를 채택 할 수 있습니다 (Redis 레코드 용 ttl 구현). Spring Boot를 사용하면 Scheduler가 자동으로 구성됩니다. 따라서 서비스 레이어에 직접 자동으로 연결할 수 있습니다.

    이러한 목적으로 Quartz를 채택 할 수 있습니다 (Redis 레코드 용 ttl 구현). Spring Boot를 사용하면 Scheduler가 자동으로 구성됩니다. 따라서 서비스 레이어에 직접 자동으로 연결할 수 있습니다.

    @Autowired
    private Scheduler scheduler;
    

    그런 다음 이와 같은 작업을 구현해야합니다 (이 예제에서는 Spring Redis Data를 사용하고 있습니다).

    @Slf4j
    @Component
    public class RemoveExpiredRecordJob implements Job {
    
    @Autowired
    public RedisRepository redisRepository;
    
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        String key = jobExecutionContext
                .getJobDetail()
                .getKey()
                .getName();
        redisRepository.deleteById(key);
        log.info("Record removed due timeout :: {}", key);
    }
    

    }

    그런 다음 JobDetail 및 Trigger를 생성하기위한 로직을 캡슐화 할 수 있습니다.

    @Component
    public class SchedulerComponentBuilder {
    
        public JobDetail getJobDetail (String key, Class<? extends org.quartz.Job> clazz) {
            return JobBuilder.newJob().ofType(clazz)
                    .storeDurably(false)
                    .withIdentity(key)
                    .withDescription("This key will be removed from Redis store when time expires.")
                    .build();
        }
    
        public Trigger getTrigger(int ttl, JobDetail jobDetail) {
            java.util.Calendar calendar = java.util.Calendar.getInstance();
            calendar.add(java.util.Calendar.SECOND, ttl);
            return TriggerBuilder.newTrigger().forJob(jobDetail)
                    .withDescription("This trigger fires once to remove an expired record from Redis store.")
                    .startAt(calendar.getTime())
                    .build();
        }
    }
    

    그리고 마지막으로 Redis 저장소에 레코드를 저장 한 직후에이 레코드 (uniqueKey)를 다음과 같이 제거 할 작업을 예약해야합니다.

    @Autowired
    private SchedulerComponentBuilder schedulerComponentBuilder;
    
    private void schedule(String uniqueKey, int ttl) {
        try {
            JobDetail jobDetail = schedulerComponentBuilder.getJobDetail(uniqueKey, RemoveExpiredRecordJob.class);
            Trigger jobTrigger = schedulerComponentBuilder.getTrigger(ttl, jobDetail);
            scheduler.scheduleJob(jobDetail,jobTrigger);
            log.info("Job is scheduled :: {}", jobDetail);
        } catch (SchedulerException e) {
            log.error("Filed to schedule a job {}", e);
            throw new RuntimeException(e);
        }
    }
    
  6. from https://stackoverflow.com/questions/34893279/spring-data-redis-expire-key by cc-by-sa and MIT license