Redis 发布订阅原理以及springboo中RedisTemplate集成
一、Redis发布订阅原理
Redis的架构包括两个部分:Redis Client和Redis Server,即客户端和服务端。客户端负责向服务器端发送请求并接受来自服务器端的响应。服务器端负责处理客户端请求
发布订阅的框架
其中Publisher(发布)和Subscriber(订阅)为Redis Client,channel为Redis server,而且发布者和订阅者是一对多的关系。
客户端和服务端可以理解为都各自维护着一个channel列表。
- (1)PUBLISH
当客户端向某个频道发送消息时,Redis首先在结构体redisServer中的pubsub_channels中找出键为该频道的结点,遍历该结点的值,找出所有的客户端,将消息发送给这些客户端。然后,遍历结构体Redis Client中的pubsub_patterns,找出包含该频道的模式的结点,将消息发送给订阅了该模式的客户端。
- 2)SUBSCRIBE
在客户端结构体client中,有一个属性为pubsub_channels,该属性表明了该客户端订阅的所有频道,它是一个字典类型,通过哈希表实现,其中的每个元素都包含了一个键值对以及指向下一个元素的指针,每次订阅都要向其中插入一个结点,键表示订阅的频道,值为空。然后,在表示服务器端的结构体redisServer中,也有一个属性为pubsub_channels,但此处它表示的是该服务器端中的所有频道以及订阅了这个频道的客户端,它也是一个字典类型,插入结点时,键表示频道,值则是订阅了这个频道的所有客户端组成的链表。最后Redis通知客户端其订阅成功。
- (3)PSUBSCRIBE
当客户端订阅某个模式时,Redis同样需要将该模式和该客户端绑定。首先,在结构体client中,有一个属性为pubsub_patterns,该属性表示该客户端订阅的所有模式,它是一个链表类型,每个结点包括了订阅的模式和指向下一个结点的指针,每次订阅某个模式时,都要向其中插入一个结点。然后,在结构体redisServer中,有一个属性也叫pubsub_patterns,它表示了该服务器端中的所有模式和订阅了这些模式的客户端,它也是一个链表类型,插入结点时,每个结点都要包含订阅的模式,以及订阅这个模式的客户端,和指向下一个结点的指针,个人理解为是一种模糊匹配
- (4)UNSUBSCRIBE(退订)
命令可以退订指定的频道, 这个命令执行的是订阅的反操作: 它从 pubsub_channels 字典的给定频道(键)中, 删除关于当前客户端的信息, 这样被退订频道的信息就不会再发送给这个客户端。
参考连接:https://redisbook.readthedocs.io/en/latest/feature/pubsub.html
二、REDIS发布订阅和监听REDIS队列的区别
使用jedis的subscribe和publish实现的发布订阅系统 PK 使用jedis的BRPOP和BLPOP实现的阻塞时消息队列
1、redis队列为阻塞队列,获取完一个信息后会主动退出,如果想一直获取信息则需要开启一个监听;而发布订阅中的订阅端是自动完成的监听。
2、redis队列中的数据取出后就消失了,无法满足多端口;而发布订阅可以将数据发布到多个channel。
3、redis队列的数据不取出就会一直在缓存中;而发布订阅中订阅获取的数据不处理就消失了。
三、ActiveMQ和REDIS发布订阅的比较
1、ActiveMQ支持多种消息协议,包括AMQP,MQTT,Stomp等(https://www.cnblogs.com/winner-0715/p/6883212.html),并且支持JMS规范;Redis没有提供对这些协议的支持
2、ActiveMQ提供持久化功能;Redis消息被发送,如果没有订阅者接收,那么消息就会丢失
3、ActiveMQ提供了消息传输保障,当客户端连接超时或事务回滚等情况发生时,消息会被重新发送给客户端;Redis没有提供消息传输保障
4、ActiveMQ所提供的功能远比Redis发布订阅要复杂,毕竟Redis不是专门做发布订阅的;如果系统能够通过mq实现,则没必要使用mq
四、springboo中RedisTemplate实现发布订阅
maven依赖
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>2.1.11.RELEASE</version></dependency>
实现redis发布订阅核心是RedisMessageListenerContainer类。它是Redis订阅发布的监听容器,你的消息发布、订阅配置都必须在这里面实现
- 其中addMessageListener(MessageListenerAdapter,PatternTopic)方法是 新增订阅频道及订阅者,订阅者必须有相关方法处理收到的消息
- MessageListenerAdapter 监听适配器
– MessageListenerAdapter(Object , defaultListenerMethod) 订阅者及其方法 - redisTemplate redis模版类
– convertAndSend(String channel, Object message) 消息发布
具体代码实现
订阅者具体代码实现
核心reidsConfig
/*** RedisTemplate配置* @author 王大宝*/
@Configuration
public class RedisConfiguration {private final Logger logger = LoggerFactory.getLogger(this.getClass());@Autowiredprivate RedisProperties redisProperties;@Bean@Primary/***redis连接配置*/public RedisConnectionFactory redisConnectionFactory() {RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration();standaloneConfig.setHostName(redisProperties.getHost()); //redis地址standaloneConfig.setPort(redisProperties.getPort());standaloneConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));//redis库。这里用的都是1号库standaloneConfig.setDatabase(redisProperties.getDatabase()); JedisPoolConfig poolConfig = new JedisPoolConfig();poolConfig.setMaxIdle(redisProperties.getJedis().getPool().getMaxIdle());poolConfig.setMinIdle(redisProperties.getJedis().getPool().getMinIdle());JedisClientConfiguration clientConfig = JedisClientConfiguration.builder().connectTimeout(Duration.ofMillis(2000)).readTimeout(Duration.ofMillis(2000)).usePooling().poolConfig(poolConfig).build();return new JedisConnectionFactory(standaloneConfig, clientConfig);}@Beanpublic MessageListenerAdapter accessTokenChangeListenerAdapter(AccessTokenChangeEvent accessTokenChangeEvent) {//监听适配器。这里需要配置具体处理订阅消息的具体方法,即:accessTokenChangeEvent(该类中实现具体处理订阅消息的代码)MessageListenerAdapter messageListener = new MessageListenerAdapter(accessTokenChangeEvent);//自定义序列化方式GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();messageListener.setSerializer(jsonRedisSerializer);return messageListener;}@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory,@Qualifier("accessTokenChangeListenerAdapter") MessageListenerAdapter accessTokenChangeListenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(redisConnectionFactory);//订阅频道。和发布消息的频道key保持一致,这里的key值为:access_token_eventChannelTopic accessTokenTopic = new ChannelTopic(ChannelRedisKey.ACCESS_TOKEN_EVENT);//向监听容器中新增订阅频道和订阅者。container.addMessageListener(accessTokenChangeListenerAdapter, accessTokenTopic);ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(2);taskExecutor.setMaxPoolSize(2);taskExecutor.setQueueCapacity(1000);ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("redis-message-listener-container-pool-%d").setUncaughtExceptionHandler((thread, exception) ->logger.error(thread.toString(), exception)).build();taskExecutor.setThreadFactory(threadFactory);taskExecutor.initialize();container.setTaskExecutor(taskExecutor);return container;}
}
其中 accessTokenChangeEvent 为具体的处理订阅消息的实现类,该类中的handleMessage()方法中是你的具体处理逻辑。
例如:
/*** accessToken订阅事件处理* @author 王大宝*/
@Configuration
public class AccessTokenChangeEvent {private Logger logger = LoggerFactory.getLogger(getClass());public void handleMessage(Map<String, Object> event, String channel) {logger.info("收到token变更事件事件:{}", event.toString());............}
}
这里为什么是handleMessage()方法?因为在创建MessageListenerAdapter 时并没有指定监听方法,默认是handleMessage
发布者代码实现:
发布者相对来说很简单,需要配置一个redisTemplate .。其中注意redis库要与订阅者保持一致。
再数据更改处,或者需要发布的地方使用redisTemplate的convertAndSend方法
例如:
//发布消息。更新内存中token
Map<String, Object> stateEvent = new HashMap<>();
redisTemplate.convertAndSend(ChannelRedisKey.ACCESS_TOKEN_EVENT,stateEvent);
Redis 发布订阅原理以及springboo中RedisTemplate集成相关推荐
- Redis发布订阅模式实现原理
前言 发布订阅系统在我们日常的工作中经常会使用到,这种场景大部分情况我们都是使用消息队列,常用的消息队列有 Kafka,RocketMQ,RabbitMQ,每一种消息队列都有其特性,很多时候我们可能不 ...
- 使用Spring Redis发布/订阅
继续发现功能强大的Redis功能集,值得一提的是对发布/订阅消息的开箱即用支持. 发布/订阅消息传递是许多软件体系结构的重要组成部分. 某些软件系统要求消息传递解决方案提供高性能,可伸缩性,队列持久性 ...
- Redis发布订阅模式
使用银行卡消费的时候,银行往往会通过微信.短信或邮件通知用户这笔交易的信息,这便是一种发布订阅模式,这里的发布是交易信息的发布,订阅则是各个渠道.这在实际工作中十分常用,Redis 支持这样的一个模式 ...
- Redis 发布订阅,小功能大用处,真没那么废材!
假设我们有这么一个业务场景,在网站下单支付以后,需要通知库存服务进行发货处理. 上面业务实现不难,我们只要让库存服务提供给相关的给口,下单支付之后只要调用库存服务即可. 后面如果又有新的业务,比如说积 ...
- Spring Boot 使用Redis发布订阅模式处理消息
Spring Boot 使用Redis发布订阅模式 1. Redis发布订阅模式 2. Spring Boot中订阅消息 2.1 Redis监听器容器配置 2.2 创建通道监听器 2.3 测试订阅功能 ...
- 5.Redis 发布订阅
转自:http://www.runoob.com/redis/redis-tutorial.html Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub ...
- google的api key调用次数是多少_Sprint Boot如何基于Redis发布订阅实现异步消息系统的同步调用?...
前言 在很多互联网应用系统中,请求处理异步化是提升系统性能一种常用的手段,而基于消息系统的异步处理由于具备高可靠性.高吞吐量的特点,因而在并发请求量比较高的互联网系统中被广泛应用.与此同时,这种方案也 ...
- 上下文管理、redis发布订阅、RabbitMQ发布订阅、SQLAlchemy
一.上下文管理 import contextlib @contextlib.contextmanager def work_state(state_list,worker_thread):state_ ...
- Redis发布订阅机制
1. 什么是Redis Redis是一个开源的内存数据库,它以键值对的形式存储数据.由于数据存储在内存中,因此Redis的速度很快,但是每次重启Redis服务时,其中的数据也会丢失,因此,Redis也 ...
最新文章
- Linux的基本指令--服务器
- hana::detail::variadic::at用法的测试程序
- Redis五种数据结构
- Three Integers CodeForces - 1311D(思维+暴力)
- python自动化办公知识点整理汇总_python自动化办公小结
- Linux系统编程学习问题回顾
- 纪中B组模拟赛总结(2019.12.21)
- java array_Java 数组
- 论文浅尝 | 「知识图谱」领域近期值得读的 6 篇顶会论文
- 使用阿基米德螺线进行数据可视化
- 【MySQL】添加多个字段
- webservice服务及客户端 编程 - 入门
- python自动生成报告_python实现自动生成oracle awr报告
- 融云php sdk下载安装,Laravel框架使用融云服务端SDK
- win7安装visio2016需要通用CRT(KB2999226)
- 全年数学建模相关比赛
- win10易升计算机丢失,易升win10害死人|win10易升怎么关闭
- 计算机组成原理不恢复余数法,计算机组成原理第七讲(除法-原码恢复余数法)(科大罗克露)...
- 风云激荡,成功者自强
- rime 简体中文 linux,Rime (简体中文)
热门文章
- 计算机应用基础7次作业答案,北京中医药大学远程教育“计算机应用基础”第7次作业(14页)-原创力文档...
- python实现骰子猜大小游戏
- 怎么讲计算机e盘设置共享,共享盘怎么设置(电脑如何设置共享盘)
- asp.net 获得根文件夹在服务器上物理路径,asp.net获取网站目录物理路径示例
- 人们对人工智能的看法(消极篇)
- matlab 双曲正割脉冲,matlab画双曲正割(急)!!!!!!!!!!!!!!!!!!!!!!...
- Win11自带微软浏览器无法翻译
- 带你走进组件化(三)—— 曲径
- [论文阅读:姿态识别Transformer] TransPose: Keypoint Localization via Transformer 2021 ICCV
- 三种方法查看电脑IP地址是否被占用