redis key过期监听

前言

通过开启key过期的事件通知,当key过期时,会发布过期事件;我们定义key过期事件的监听器,当key过期时,就能收到回调通知。但是这个只能是测试或者简单的场景使用,最好不要在生产上使用,尤其是大项目,可能不太靠谱,下面讲一下如果使用

使用场景

消息作为key,将需要延迟的时间设置为key的TTL,当key过期时,在监听器收到通知,达到延迟的效果,不如订单过期通知,订单需要10分钟内支付,过期后需要变更为已取消

配置

需要修改redis.conf配置文件

1
notify-keyspace-events Ex

在配置文件搜索notify-keyspace-events,默认后面是 “”,两个双引号,删除,改为 Ex即可

使用

java代码,先订阅

1
2
3
4
5
6
7
8
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
// redis 消息订阅(监听)者容器
RedisMessageListenerContainer messageListenerContainer = new RedisMessageListenerContainer();
messageListenerContainer.setConnectionFactory(redisConnectionFactory);
// messageListenerContainer.addMessageListener(new ProductUpdateListener(), new PatternTopic("*.product.update"));
return messageListenerContainer;
}

再监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

/**
* 创建RedisKeyExpirationListener bean时注入 redisMessageListenerContainer
*
* @param redisMessageListenerContainer RedisConfig中配置的消息监听者容器bean
*/
public RedisKeyExpirationListener(RedisMessageListenerContainer redisMessageListenerContainer) {
super(redisMessageListenerContainer);
}

@Override
public void onMessage(Message message, byte[] pattern) {
String channel = new String(message.getChannel()); // __keyevent@*__:expired
String pa = new String(pattern); // __keyevent@*__:expired
String expiredKey = message.toString();
System.out.println("监听到过期key:" + expiredKey);
}
}

注意:

  1)由于Redis key过期删除是定时+惰性,当key过多时,删除会有延迟,回调通知同样会有延迟。因此性能较低

  2)且通知是一次性的,没有ack机制,若收到通知后处理失败,将不再收到通知。需自行保证收到通知后处理成功。

  3)通知只能拿到key,拿不到value

  4)Redis将数据存储在内存中,如果遇到恶意下单或者刷单的将会给内存带来巨大压力

所有,如果生产上有需求,最好是使用带延迟功能消息中间件(比如pulsar)