消息过期通知-reids keyspace notifications
了解到使用reids中keyspace notifications
功能可以实现消息过期通知
打开redis中keyspace notifications功能
默认情况下,redis中的keyspace notifications
功能是关闭的,打开这个功能也非常简单。打开redis.conf
文件,找到nofity-keyspace-events
一行:
# 关闭就是空字符串 ""
# notify-keyspace-events ""
# 打开,这里是是过期事件才会通知
notify-keyspace-events Ex
支持的事件:
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)
A Alias for g$lshzxe, so that the "AKE" string means all the events.
通知订阅
继承JedisPubSub
:
@Component
public class KeySpaceNotifySub extends JedisPubSub {
private static final Logger LOGGER = LoggerFactory.getLogger(KeySpaceNotifySub.class);
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
LOGGER.info("onPSubscribe "+pattern + "=" + subscribedChannels);
}
@Override
public void onPMessage(String pattern, String channel, String message) {
System.out.println(pattern+": "+ channel +": "+ message);
}
}
随着spring容器启动而订阅(因为redis中的psubscribe
操作是阻塞,所以这里重新开启一个线程订阅,不然会一直阻塞web容器,web运行不了):
public class KeySpaceNotifyInitializeBean implements InitializingBean {
@Autowired
private JedisPool jedisPool;
@Autowired
private KeySpaceNotifySub keySpaceNotifySub;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("KeySpaceNotifyInitializeBean...");
Thread thread = new Thread(() -> {
jedisPool.getResource().psubscribe(keySpaceNotifySub,"__keyevent@0__:expired");
});
thread.start();
}
}
spring-context.xml
配置:
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" ref="jedisPoolConfig"/>
<constructor-arg index="1" value="${redis.host}" type="java.lang.String"/>
<constructor-arg index="2" value="${redis.port}" type="int"/>
<!--<constructor-arg index="3" value="${redis.timeout}" type="int"/>-->
<!--<constructor-arg index="4" value="${redis.pass}" type="java.lang.String"/>-->
</bean>
<bean id="keySpaceNotifyInitializeBean" class="com.**.yjy.keynotify.KeySpaceNotifyInitializeBean" />
测试:
127.0.0.1:6379> setEx name 5 hello
OK
127.0.0.1:6379> setEx world 5 world
OK
可以在控制台看到:
KeySpaceNotifyInitializeBean...
[2018-07-22 16:52:27.298] [ INFO] KeySpaceNotifySub onPSubscribe __keyevent@0__:expired=1
...
[2018-07-22 04:52:27,545] Artifact spring-mvc-demo:war exploded: Artifact is deployed successfully
[2018-07-22 04:52:27,545] Artifact spring-mvc-demo:war exploded: Deploy took 5,367 milliseconds
__keyevent@0__:expired: __keyevent@0__:expired: name
__keyevent@0__:expired: __keyevent@0__:expired: world
注意:redis中的expire事件,并不是根据ttl键名为0的时候触发的,而是在真正删除了过期键(key)的时候才触发的。如果删除时间和ttl时间存在时间差,那么通知就不会那么的精确