Redis 发布订阅及key过期通知!
1,应用场景:
订单过期时间可以通过redis缓存进行存放,然后redis过期之后,处理订单超时可以使用redis 的键过期触发事件通知!
redis在 2.8.0(4.0以后就开始收费了)以后的版本提供了,KeySpace Notification功能,允许客户订阅pub/Sub频道,以便以某种方式接收影响redis数据集事件。
接下来实际操作:
先看看自己的redis版本:
我这是3.0的版本,是支持这个事件的
2,修改redis的配置文件,怎么看,
应该很清晰,找到redis的配置文件之后,打开 keySpace Notification 的功能,
先看一下
Elg 这里是组合的命令,以上不多说,重点是我们配置一下:
修改redis.conf 文件,修改notify-keyspace-events Ex
配置完成, 重启redis服务就可以了
实现:
1,事件通过redis 的订阅与发布功能来进行分发,
所以需要订阅 keyevent@0:expired 通道表示db0 根据自己的dbindex选择合适的数字
开始编码:
static void Main(string[] args)
{
const string MessagePrefix = "Pay_OrderID_";
const int PublishMessageCount = 5;
Console.WriteLine("Begin publishing order messages...");
using (var redisPublisher = new RedisClient(RedisConfig.Host, RedisConfig.Port, RedisConfig.Password, 1)) //redis默认有15个库,这里的1意思是使用 db1,默认是0
{
Random random = new Random();
for (var i = 1; i <= PublishMessageCount; i++)
{
var message = MessagePrefix + i;
int expirySeconds = random.Next(1, 10);
Console.WriteLine(String.Format("{0} Publishing '{1}' expirySeconds '{2}'", DateTime.Now.ToString(), message, expirySeconds));
redisPublisher.Set(key: message, value: message + Guid.NewGuid().ToString("N"), expiresIn: TimeSpan.FromSeconds(expirySeconds));
}
}
Console.WriteLine("End publishing order messages...");
Console.ReadKey();
}
简单的生成5个key,随机给的过期时间,1-10秒,看看生成者实现了效果没有
结果是OK的,key我是放在db1里面的,接下里要去订阅一下key 的过期事件,相当于消费:
static void Main(string[] args)
{
//K 键空间通知,所有通知以 keyspace@ 为前缀,这里的event指的是redis中的命令比如del、expired、list、set
//E 键事件通知,所有通知以 keyevent@ 为前缀,
// "__keyevent@0__:expired" 0表示db0根据自己的dbindex选择合适的数字。
//其中必选K或E,比如开启过期通知,“Ex”或者"Kx",两者的区别在于事件名不同,不过我们可以采用模糊订阅的方式,如果开启所有事件则是“AKE”
//redis默认是关闭这个特性的,因为打开这个特性,会消耗一定的CPU资源。故实际业务场景中我们尽量发布和订阅都约定好指定的Redis dbIndex存储空间。这样就不需要全库(0-16)去检索,否则太浪费性能了。
//因为 Redis 目前的订阅与发布功能采取的是发送即忘策略, 所以如果你的程序需要可靠事件通知, 那么目前的键空间通知可能并不适合你:当订阅事件的客户端断开连接时,当再次连接上的时候, 它会丢失所有在断开连接期间分发给它的事件。
/*
举例:当 del mykey 命令执行时:
K键空间频道的订阅者将接收到被执行的事件的名字,在这个例子中,就是 del 。
E键事件频道的订阅者将接收到被执行事件的键的名字,在这个例子中,就是 mykey 。
*/
//1、以事件为出发点。配置文件修改为:notify-keyspace-events Kx
//const string ChannelName = "__keyspace@0__:Pay_OrderID_1";//监听Key所操作的事件(命令)
//const string ChannelName = "__keyspace@0__:expired";//监听Key所操作的事件(命令)
//2、以Key为出发点。配置文件修改为:notify-keyspace-events Ex
const string ChannelName = "__keyevent@0__:expired";//监听Key键。但是无法监听到Key所对应的值。
const string MessagePrefix = "Pay_OrderID_";
Console.WriteLine("Starting Received order messages...");
using (var redisConsumer = new RedisClient(RedisConfig.Host, RedisConfig.Port, RedisConfig.Password))
using (var subscription = redisConsumer.CreateSubscription())
{
subscription.OnSubscribe = channel =>
{
Console.WriteLine(String.Format("Subscribed to '{0}'", channel));
};
subscription.OnUnSubscribe = channel =>
{
Console.WriteLine(String.Format("UnSubscribed from '{0}'", channel));
};
subscription.OnMessage = (channel, msg) =>
{
if (msg.StartsWith(MessagePrefix))//根据具体的业务标识来匹配筛选获取。(由于通知收到的是redis key,value已经过期,无法收到,所以需要在key上标记业务数据。)
{
Console.WriteLine(String.Format(" {0} Received '{1}' from channel '{2}'", DateTime.Now.ToString(), msg, channel));
}
};
subscription.SubscribeToChannels(ChannelName); //blocking
//subscription.SubscribeToChannels(ChannelName, ChannelName, ChannelName); // 订阅 subscribe: 订阅具体键名, 支持一次可以订阅多个
}
}
暂时写到这,欢迎指点!