一、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集成相关推荐

  1. Redis发布订阅模式实现原理

    前言 发布订阅系统在我们日常的工作中经常会使用到,这种场景大部分情况我们都是使用消息队列,常用的消息队列有 Kafka,RocketMQ,RabbitMQ,每一种消息队列都有其特性,很多时候我们可能不 ...

  2. 使用Spring Redis发布/订阅

    继续发现功能强大的Redis功能集,值得一提的是对发布/订阅消息的开箱即用支持. 发布/订阅消息传递是许多软件体系结构的重要组成部分. 某些软件系统要求消息传递解决方案提供高性能,可伸缩性,队列持久性 ...

  3. Redis发布订阅模式

    使用银行卡消费的时候,银行往往会通过微信.短信或邮件通知用户这笔交易的信息,这便是一种发布订阅模式,这里的发布是交易信息的发布,订阅则是各个渠道.这在实际工作中十分常用,Redis 支持这样的一个模式 ...

  4. Redis 发布订阅,小功能大用处,真没那么废材!

    假设我们有这么一个业务场景,在网站下单支付以后,需要通知库存服务进行发货处理. 上面业务实现不难,我们只要让库存服务提供给相关的给口,下单支付之后只要调用库存服务即可. 后面如果又有新的业务,比如说积 ...

  5. Spring Boot 使用Redis发布订阅模式处理消息

    Spring Boot 使用Redis发布订阅模式 1. Redis发布订阅模式 2. Spring Boot中订阅消息 2.1 Redis监听器容器配置 2.2 创建通道监听器 2.3 测试订阅功能 ...

  6. 5.Redis 发布订阅

    转自:http://www.runoob.com/redis/redis-tutorial.html Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub ...

  7. google的api key调用次数是多少_Sprint Boot如何基于Redis发布订阅实现异步消息系统的同步调用?...

    前言 在很多互联网应用系统中,请求处理异步化是提升系统性能一种常用的手段,而基于消息系统的异步处理由于具备高可靠性.高吞吐量的特点,因而在并发请求量比较高的互联网系统中被广泛应用.与此同时,这种方案也 ...

  8. 上下文管理、redis发布订阅、RabbitMQ发布订阅、SQLAlchemy

    一.上下文管理 import contextlib @contextlib.contextmanager def work_state(state_list,worker_thread):state_ ...

  9. Redis发布订阅机制

    1. 什么是Redis Redis是一个开源的内存数据库,它以键值对的形式存储数据.由于数据存储在内存中,因此Redis的速度很快,但是每次重启Redis服务时,其中的数据也会丢失,因此,Redis也 ...

最新文章

  1. linux进程间通信:FIFO应用 /var/log/ 系统日志的模拟实现
  2. 2010提高组-乌龟棋 [记忆优化搜索]
  3. 使用工具类创建一个线程池
  4. 【图灵有聊】说好的安全呢?
  5. springboot 事务手动回滚_Spring Boot中的事务是如何实现的
  6. Httpd之检测与安装
  7. python tensorflow tf.Session().run()函数(运行操作并评估“fetches”中的张量)
  8. java虚拟机常用命令工具
  9. VS中的lib和dll的区别和使用
  10. UVA 572 Oil Deposits(DFS求连通块)
  11. 21. 总是让比较函数在等值情况下返回false
  12. 【图像增强】基于matlab可见边缘梯度比率图像增强【含Matlab源码 1404期】
  13. 海康威视错误代码说明(一)(错误代码:1~14)
  14. windows域的创建
  15. Postgresql计算月天数
  16. 李沐动手学深度学习_环境搭建
  17. 无线通讯 cmt2150A 简介 1527协议
  18. verilog设计简易正弦波信号发生器_FPGA学习(一)——产生频率可控的正弦波
  19. 今晚7:30 | CVPR专场四!UIUC、港中文、港科大
  20. 163邮箱vip会员体系,看收费邮箱行业未来!

热门文章

  1. 百万年薪python之路 -- 软件的开发规范
  2. 网页版本模拟linux,Firefox OS 模拟器
  3. 关于悬浮窗Settings.canDrawOverlays获取权限是否开通出错
  4. python决策树实例_机器学习中的决策树及python实例
  5. Akamai阿卡迈_abck逆向sensor_data(一)
  6. 谷歌浏览器提示“喔唷,崩溃啦!”
  7. java 兔子问题_Java算法之“兔子问题”
  8. 后缀是lnk是什么文件_lnk文件怎么打开?lnk是什么文件?
  9. android 腾讯x5内核 浏览器
  10. openCV教程01