Redis键通知(事件通知)
通常,对于Redis这款中间件,最多的应该是作为缓存来使用,比较好的做法是会给Redis中的key设置一个过期时间,过期之后自动删除。那么,我们可能会有这样的需求,如果一个key被删除了,或者过期了,能否通知使用redis的应用程序呢,其实是有方法的。
从Redis:2.8.0开始,提供了键空间通知的功能,详见官方文档Redis Keyspace Notifications - Redis 。原理就是基于Redis的PUB/SUB机制,当键被发生了某种操作时,Redis会往特定的channel发布特定格式的消息,Redis客户端订阅相关channel就可以接受到消息并作相应的处理。
channel格式:keyevent@数据库ID:操作类型
__keyevent@0__:del
__keyevent@0__:expired
...
默认情况下,Redis键通知功能是禁用的,开启需要在配置文件中增加名字为notify-keyspace-events的配置,具体值配置为多少,官方文档中其实也给出了
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
t Stream commands
d Module key type events
x Expired events (events generated every time a key expires)
e Evicted events (events generated when a key is evicted for maxmemory)
m Key miss events (events generated when a key that doesn't exist is accessed)
A Alias for "g$lshztxed", so that the "AKE" string means all the events except "m".
我们需要接收键事件,E必须配置,否则其他配置不生效,具体怎么组合,看具体使用场景,举些例子
Eg 对某个键调用DEL,EXPIRE操作时,会收到通知
Ex 当某个键过期后会收到通知
Em 当检索某个不存在的键时会收到通知
开始具体实操一下,需求监听键过期事件
- 修改redis.conf配置文件并重启Redis
- 新建Maven项目,导入Redis相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置监听器容器
@Configuration
public class RedisConfig {
@Bean
public RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(new KeyExpirationMessageListener(), new PatternTopic("__keyevent@0__:expired"));
return container;
}
}
@Slf4j
public class KeyExpirationMessageListener implements MessageListener {
@Override
public void onMessage(Message message, byte[] pattern) {
log.info("监听到键过期消息,消息内容:{},消息对应的键为:{}", message, new String(pattern));
}
}
- 启动项目,使用Redis客户端设置一个键,超时时间设置为10秒钟,观察控制台打印信息
- 当然,这是一种通用的配置方式,但如果仅仅是为了接收键过期提醒,可以使用spring-boot-starter-data-redis依赖中提供的KeyExpirationEventMessageListener监听器,本身已经实现了MessageListener接口,同时,又实现了ApplicationEventPublisherAware接口,具备了使用Spring事件驱动的功能
使用时需要配置RedisMessageListenerContainer、KeyExpirationEventMessageListener、ApplicationListener
@Slf4j
@Configuration
public class RedisConfig {
@Bean
public RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
@Bean
public KeyExpirationEventMessageListener keyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer) {
return new KeyExpirationEventMessageListener(listenerContainer);
}
@Bean
public ApplicationListener applicationListener() {
return (ApplicationListener<RedisKeyExpiredEvent>) event -> {
log.info("监听到键过期消息,消息对应的键为:{},消息所属的channel为:{}", new String(event.getSource()), event.getChannel());
};
}
}
同样的,会在控制台看到相关信息 最后,需要说明的一点,Redis的键通知功能并不是一种完全可靠的机制,某些情况下通知不可达,比如因为网络问题导致应用跟Redis server断线重连,那么在断线时间范围内,有键触发了通知也无法送达应用,且事后无补偿,所以在可靠性要求很高的场景下并不适用。
|