叙述
Keyspace 通知使得客户端可以通过订阅频道或模式,来接收那些以某种方式改动了 Redis 数据集的事件(触发某些事件后可以向指定的频道发送通知),该功能需要 Redis 版本大于 2.8。
事件通过 Redis 的订阅与发布功能(pub/sub)来进行分发,因此所有支持订阅与发布功能的客户端都可以在无须做任何修改的情况下,直接使用此功能。
因为 Redis 目前的订阅与发布功能采取的是发送即忘(fire and forget)策略,所以如果你的程序需要可靠事件通知(reliable notification of events),那么目前的键空间通知可能并不适合你:当订阅事件的客户端断线时,它会丢失所有在断线期间分发给它的事件。
事件类型
对于每个修改数据库的操作,键空间通知都会发送两种不同类型的事件:键空间通知(key-space)和键事件通知(key-event)。
当 del mykey 命令执行时:
- 键空间频道的订阅者将接收到被执行的事件的名字,在这个例子中,就是 del
- 键事件频道的订阅者将接收到被执行事件的键的名字,在这个例子中,就是 mykey
因为开启键空间通知功能需要消耗一些 CPU,所以在默认配置下,该功能处于关闭状态。
修改 redis.conf 中的 notify-keyspace-events 参数,参数可以是以下字符的任意组合, 它指定了服务器该发送哪些类型的通知:
输入的参数中至少要有一个 K 或者 E,否则的话,不管其余的参数是什么,都不会有任何通知被分发。
如: notify-keyspace-events "Ex" 表示对过期事件进行通知发送; notify-keyspace-events "kx" 表示想监控某个 key 的失效事件。将参数设为字符串 AKE 表示发送所有类型的通知。
演示
客户端订阅 subscribe __keyevent@0__:expired
在另一个客户端执行 setex name 10 txl ,10 秒过后,订阅端就会接收到消息:
教程
Redis配置
修改配置文件redis.conf(Windows为redis.windows.conf)
- 打开该配置文件(位置取决于自己的安装位置),找到Event notification部分。
- 将notify-keyspace-events Ex的注释打开或者添加该配置,其中E代表Keyevent,此种通知会返回key的名字,x代表超时事件。
- 如果notify-keyspace-events ""配置没有被注释的话要注释掉,否则不会生效。
- 保存后重启redis,一定要使用当前配置文件重启,例如src/redis-server redis.conf
springboot配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
redis:
# 连接超时 毫秒
connectTimeout: 1800
# 运行超时 毫秒
timeout: 7200
host: 127.0.0.1
port: 6379
database: 1
password:
jedis:
pool:
# 最大空闲(cpu*2)
maxIdle: 16
# 最小空闲
minIdle: 0
# 最大阻塞等待时间(负数表示没限制)毫秒
maxWait: 3600
# 最大连接数(大于cpu*2)
maxActive: 24
# 键事件过期监听 1 代表使用了哪个DB 参考 database
listen:
keyEvent: __keyevent@1__:expired
@Data
@Component
@ConfigurationProperties(
prefix = "spring.redis.listen"
)
public class RedisProperties {
private String keyEvent;
}
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory;
@Autowired
private RedisProperties redisProperties;
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
@Bean
public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
return redisTemplate.opsForValue();
}
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
/**
* redis消息监听器容器
* 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
*/
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic(redisProperties.getKeyEvent()));
return container;
}
/**
* keyEvent 专用
*/
@Bean
public MessageListenerAdapter listenerAdapter(KeyEventReceiver receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
}
@Component
public class KeyEventReceiver {
//监听键事件,过期事件
public void receiveMessage(String message) throws Exception {
log.error("过期键 <" + message + ">");
}
}