一、前言:
不谈应用场景的技术都是道听途说;
二、应用场景
1.1 需求一:
-
一个交易系统里面有一个价格提醒的功能,用户可以设置一组价格并设置一个周期,后台需要在交易的时间内进行价格扫描一旦触发用户设置的价格的周期就需要下发消息提醒给用户,提醒用户交易做单;
-
具体要求如下:交易系统都需要考虑实时性,所以后台的扫描周期为2s,用户量为公司所管理的宇宙第一行的先行客户
-
从上述的描述中我们可以发现,用户量还是比较大,其实实时性要求比较高,所以如果我们把数据落库,然后每次定时的时候从数据库里面去取然后做逻辑的判断,这样肯定是无法达到实时性的要求的,所以我们准备采用redis来管理这批数据。但是也有一个问题,当这批数据过期的时候,一、要提醒用户,二、从redis删除后,要设置数据库的状态。要解决这个功能就需要使用到redis的一个高级的功能:redis 的订阅/发布功能,只不过超时的事件时有系统进行分发。
1.2 需求二:
- 订单超时自动关闭的问题,这个就不详细的描述了,因为大家购物相信都能体验的到。与此相关的问题还有一个就是库存锁定的问题,问题都是一样的。
- 这个问题解决的方案就有多种了,我们可以通过MQ来进行,现在大多的MQ都带有死信队列的机制,我们可以通过这个机制来完成,其次也可以通过quartz的轮询方式的完成,过程不表选择合适的应对当前的需求即可。当然本次主要是解决第一个需求,所以只谈如何使用redis来解决。
三、具体实施:
3.1 修改 redis.conf配置文件:
- K Keyspace events, published with keyspace@ prefix事件
- E Keyevent events, published with keyevent@ 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.
redis.conf 的默认的配置是:notify-keyspace-events “”
我们需要改为:notify-keyspace-events Ex
即对应上面的键的过期事件。修改玩这个重启一下redis
3.2 客户端来监听redis的过期事件:
3.2.1 springboot + redis 的情况下的监听:
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;
}
}
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = message.toString();
System.out.println(expiredKey);
}
}
需要注意的是:
过期监听消息中返回的是,过期的键的key值,是没有返回value的
3.2.2 spring+ redis+ jedis 的情况下的监听:
class KeyExpiredListener extends JedisPubSub {
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
System.out.println("onPSubscribe " + pattern + " " + subscribedChannels);
}
@Override
public void onPMessage(String pattern, String channel, String message) {
System.out.println(
"pattern = [" + pattern + "], channel = [" + channel + "], message = [" + message + "]");
}
}
然后在配置文件中配置 KeyExpiredListener 即可
四、思考:
就如同我们上述的例子,订单和商品锁定5分钟的例子,我们两个地方都是需要进行监听的,但是有可能还有其他的地方需要使用的到,所以我们只写一个监听,然后采用类似观察者的模式,将需要处理这种key过期的处理程序进行注册,在监听里面去调用就好了。下一篇博文在讲个这。