1.技术背景,想知道 redis 设置了TTL时间的key 过期,且有后续的业务处理的场景可以使用。
bug点:
使用redis 缓存失效监听会有一定的延迟, 过期事件是在redis服务器删除键的时候生成的,而不是在理论上生存时间到达0值得时候生成的。
搭建:
1.前置条件为 redis服务器端开启了事件通知。配置文件redis.conf文件中 开启相关配置。
默认情况下redis是未开启事件通知的。
############################# EVENT NOTIFICATION ##############################
# Redis can notify Pub/Sub clients about events happening in the key space.
# This feature is documented at https://redis.io/topics/notifications
#
# For instance if keyspace events notification is enabled, and a client
# performs a DEL operation on key "foo" stored in the Database 0, two
# messages will be published via Pub/Sub:
#
# PUBLISH __keyspace@0__:foo del
# PUBLISH __keyevent@0__:del foo
#
# It is possible to select the events that Redis will notify among a set
# of classes. Every class is identified by a single character:
#
# K Keyspace events, published with __keyspace@<db>__ prefix.
# E Keyevent events, published with __keyevent@<db>__ prefix.
# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
# $ String commands
# l List commands
# s Set commands
# h Hash commands
# z Sorted set commands
# x Expired events (events generated every time a key expires)
# e Evicted events (events generated when a key is evicted for maxmemory)
# t Stream commands
# d Module key type events
# m Key-miss events (Note: It is not included in the 'A' class)
# A Alias for g$lshzxetd, so that the "AKE" string means all the events
# (Except key-miss events which are excluded from 'A' due to their
# unique nature).
#
# The "notify-keyspace-events" takes as argument a string that is composed
# of zero or multiple characters. The empty string means that notifications
# are disabled.
#
# By default all notifications are disabled because most users don't need
# this feature and the feature has some overhead. Note that if you don't
# specify at least one of K or E, no events will be delivered.
# notify-keyspace-events ""
# 配置文件修改项
notify-keyspace-events "Ex"
可直接修改 notify-keyspace-events “Ex” 即为开启了rediss 事件监听,然后重启redis 服务(或者使用命令的形式,不需要重启redis服务)。不同key 类型的监听见上文档。
2.项目中编写相关的监听程序(前置条件,redis已经集成进项目里了)
import com.jinyi.up.user.listener.RedisKeyExpirationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
/**
* spring容器 里通过 java配置方式注入RedisMessageListenerContainer 和 KeyExpirationEventMessageListener的实现类
* @author jinyi
* @date 2023/11/25 16:39
* @desc
*/
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
listenerContainer.setConnectionFactory(connectionFactory);
return listenerContainer;
}
@Bean
KeyExpirationEventMessageListener redisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
return new RedisKeyExpirationListener(listenerContainer);
}
}
import lombok.extern.slf4j.Slf4j;
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;
/**
* 使用redis 缓存失效监听会有一定的延迟, 过期事件是在redis服务器删除键的时候生成的,而不是在理论上生存时间到达0值得时候生成的,
*
* @author jinyi
* @date 2023/11/25 16:40
* @desc
*/
@Slf4j
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* 针对redis数据失效事件,进行数据处理
*
* @param message key的信息,并不包含缓存值。
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
//获得失效的key
log.info("KeyExpiration key:" + message);
//todo 后续的业务处理
}
}