Java實現Redis過期數據清除

1 過期策略

1.0 定期刪除

  • 主動刪除
  • 定期刪除設置一個時間間隔,每個時間段都會檢測是否有鍵過期,定期隨機抽取鍵檢查和刪除.

1.2 惰性刪除

  • 被動刪除
  • 惰性刪除不會在鍵過期是立即刪除,而是當外部獲取這個鍵時刪除.

1.3 定時刪除

  • 主動刪除
  • 創建鍵時設置過期時間,創建一個定時器,當鍵達到過期時間閾值時,立即刪除鍵,刪除該時刻過期的所有鍵,不會考慮此時機器所處狀態.

2 內存淘汰

序號 策略 描述
1 noeviction 當內存不足以存儲新數據寫入時,新寫入操作報錯
2 allkeys-lru 當內存不足以存儲新數據寫入時,在鍵空間中移除最近最少使用的key
3 allkeys-random 當內存不足以存儲新數據寫入時,在鍵空間中隨機移除某個key
4 volatile-lru 當內存不足以存儲新數據寫入時,在設置了過期時間的鍵中,移除最近最少使用的key
5 volatile-random 當內存不足以存儲新數據寫入時,在設置了過期時間的鍵中,隨機移除某個key
6 volatile-ttl 當內存不足以存儲新數據寫入時,在設置了過期時間的鍵中,優先移除有更早過期時間的key

3 數據過期提醒

3.1 配置過期提醒

sudo vim /etc/redis/redis.conf
notify-keyspace-events Ex

3.2 配置監聽

package com.sb.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;


import java.io.Serializable;
import java.time.Duration;
import java.lang.reflect.Method;

@Configuration 
@EnableCaching
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport{
    @Autowired 
    private RedisConnectionFactory redisConnectionFactory;
    @Bean 
    public KeyGenerator wiselyKeyGenerator(){
        return new KeyGenerator(){
            @Override 
            public Object generate(Object target, Method method, Object... params){
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for(Object obj:params){
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

   
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
                                                            .defaultCacheConfig()
                                                            .entryTtl(Duration.ofSeconds(60));
        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
                .cacheDefaults(redisCacheConfiguration).build();

    }

    @Bean 
    public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory redisConnectionFactory){
        RedisTemplate<String, Serializable> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    
    @Bean 
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory){
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
}

3.3 配置事件處理

package com.sb.util;

import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component 
public class RedisKeyExpirationListenerUtil extends KeyExpirationEventMessageListener{
    static Logger logger = LoggerFactory.getLogger(RedisKeyExpirationListenerUtil.class);
    public RedisKeyExpirationListenerUtil(RedisMessageListenerContainer listenerContainer){
        super(listenerContainer);
    }

    @Override 
    public void onMessage(Message message, byte[] pattern){
        String expiredKey = message.toString();
        // TODO
        logger.info("data expired:{}", expiredKey);
    }
}

4 小結

序號 描述
1 Redis過期清除策略有三種,定期清除,定時清除,惰性清除,其中惰性清除爲被動清除,定時和定期爲主動清除,定期爲定期隨機清除,定時爲清除所有過期數據
2 數據過期事件提醒配置Redis提醒,設定監聽容器及監聽事件,監聽事件中執行清除數據時的邏輯,同時可獲取刪除的key,通過key和持久化的數據庫同步數據
3 緩存過期數據和硬盤數據同步存儲,過期時同步刪除,保證服務宕機數據不丟失

【參考文獻】
[1]https://www.cnblogs.com/mengchunchen/p/10039467.html
[2]https://blog.csdn.net/qq_35981283/article/details/70156422
[3]https://www.jianshu.com/p/c37ad337146f
[4]https://www.jianshu.com/p/106f0eae07c8
[5]https://blog.csdn.net/m0_37367413/article/details/84320562

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章