一、什么是pub/sub?
publish/subscribe ,即发布订阅功能。基于实践系统中,是常用的通信模型,采用事件做为基本的通信机制,提供大规模系统要求的松散耦合的交互方式。订阅者,以事件定义的方式表达出它有兴趣接受的一个时间或一类事件。发布者,发布事件并通知相关订阅者。
同时,pub/sub也是一个消息通信模式,主要目的是解除消息发布者和订阅者之间的耦合,Redis作为pub/sub的一个server,在发布者和订阅者之间起到了消息路由的作用。
二、Redis实现原理简单总结
pub/sub功能提供两种信息机制,分别是“订阅/发布到频道”和“订阅/发布到模式”。
1、频道的订阅与信息发送
语法介绍: 【订阅频道】subscribe channel1 channel2 ··· 【频道发布信息】publish channel1 message 【退订频道】unsubscribe channel1 ···
订阅频道的存储:在redis服务中都维持着一个表示服务器状态的 redis.h/redisServer结构,结构中pubsub_channels属性是一个字典,用于保存订阅信息。
保存结构:该字典是一个键值对,键为正在被订阅的频道,值则是一个链表,链表中保存所有订阅这个频道的客户端。
struct redisServer {
//...
dict *pubsub_channels;
//...
}
当再次发生订阅操作,先遍历pubsub_channels的键,如果有就在对应值的链表结尾添加客户端信息。
因此程序可以通过pubsub_channels来确定某个频道是否正被订阅,也可以通过频道拿到所有订阅该频道的客户端信息。
频道发布信息:在某频道发布信息,遍历pubsub_channels找到订阅该频道的所有客户端,发送信息。
2、模式的订阅与信息发送
语法介绍:【订阅模式】psubscribe channel* ··· 【punsubscribe channel* ···】
订阅模式的存储: redisServer.pubsub_patterns属性是一个链表,链表中每个节点都包含一个redis.h/pubsubPattern结构。
pubsubPattern中client保存订阅模式的客户端,pattern则保存被订阅的模式。
struct redisServer { typedef struct pubsubPattern {
//... redisClient *client;
list *pubsub_patterns; robj *pattern;
//... } pubsubPattern;
};
发布信息:除了遍历频道外,还需匹配模式,然后发送信息。
三、项目中应用
参照项目:com.liuxs.runToExpert.redis.pubSub.plus
注意点:
1、发布和订阅主要依赖于 redis.clients.jedis.JedisPubSub 监听器,所有操作都会在其实现类中对应方法做监听处理。
2、如果用同一个jedis对象(即使没有做单例,从jedisPool中拿的)来发布、订阅,都会抛出一个异常。
异常信息:JedisDataException: ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in...
3、取消订阅功能,只有在监听过程中调用器父类的unsubsribe(channel)实现,如果直接调用抛出会找不到Client异常。