2022
我们一起努力

redis订阅为什么阻塞(redis订阅发布缺点)

目录:

  • 1、骆驼redis组件订阅渠道不工作问题,怎么解决
  • 2、什么是Redis发布订阅
  • 3、Redis实现不可靠发布/订阅功能
  • 4、redis为什么总是把订阅/发布和消息队列联系在一起
  • 5、jedis订阅发布故障处理
  • 6、Redis可能会阻塞的情况

骆驼redis组件订阅渠道不工作问题,怎么解决

使用Redis的发布订阅功能 redis另一个常见的用途是发布订阅功能 。

它非常的简单 ,当连接失败时 ConnectionMultiplexer 会自动重新进行订阅 。 ISubscriber sub = redis.GetSubscriber(); GetSubscriber 方法返回一个 ISubscriber 类型的实例 。

什么是Redis发布订阅

subscribe是一个阻塞的方法,在取消订阅该频道前,会一直阻塞在这,只有当取消了订阅才会执行下面的other code,参考上面代码,我在onMessage里面收到消息后,调用了this.unsubscribe(); 来取消订阅,这样才会执行后面的other code!

Redis实现不可靠发布/订阅功能

Redis 通过 PUBLISH 、 SUBSCRIBE 等命令实现了订阅与发布模式, 这个功能提供两种信息机制, 分别是订阅/发布到频道和订阅/发布到模式, 本文讨论订阅/发布到频道的实现

如图展示了发布消息到 channel1 后,各个client都会接收到 message

虽然Redis能够实现发布/订阅的功能,但是有如下缺点,所以选用前需谨慎考虑

由于Redis发布/订阅模型存在的缺陷,所以使用前需要考虑如下几点

具体使用还是需要考虑业务场景需求

在目前SpringBoot使用Redis的操作中,官方推荐使用SpringData模块中的 spring-data-redis ,所以下文会以 spring-data-redis 进行

序列化使用的是 GenericJackson2JsonRedisSerializer ,使用这个类可以正确序列化Null的对象.如果使用 Jackson2JsonRedisSerializer ,会将对象序列号成空数组.

简单起见,在这里使用SpringSchedule,周期性发布消息

在订阅程序中,有两个比较重要的类,分别是 MessageListenerAdapter 和 RedisMessageListenerContainer

其中 MessageListenerAdapter 实现 MessageListener 作用是将自定义的消费类进行适配.这个类必须有一个 public 的消费方法,并且方法需要有两个参数,arg1为 channel ,arg2是 Message .原因可以在 MessageListenerAdapter 源码中发现

在 MessageListenerAdapter.onMessage 方法中,通过反射对消费类进行了方法调用,并且方法的参数和顺序进行了硬编码,所以必须在消费类中提供一个public方法

从官方文档中,可以得知 RedisMessageListenerContainer 的作用是用于接收消息后进行分发,并且通过内部的线程池进行异步分发,(也可以使用自定义的线程池和相关失败策略)

启动一个发布者,两个订阅者

redis为什么总是把订阅/发布和消息队列联系在一起

这里边你所谓的单独起一个线程,实际上实现的就是监听嘛,消息发布者实际就是你在往队列里面压数据,而消息订阅者就是你写的线程来读取。

所以,这里面,队列是一种数据结构,而你所说的发布者/订阅者其实就是想要做的事的一种模式,通过队列来进行存储实现了,也不一定非用队列的,用SortSet进行值排序,一样可以称之为队列。

jedis订阅发布故障处理

redis订阅主题数过一段时间就减少,导致订阅的进程无法收到生产者publish的消息。

启动订阅进程,启动发布进程。分别断开与redis之前的网络连接,发现jedis断开后又重连连上了,通过redis命令pubsub命令查询订阅数,发现订阅数减少了。由此证明当网络中断后订阅丢失。然而jedis.subscribe并不会异常退出,而是一直卡在这个方法中,故没法根据异常退出方法重新订阅。

redis发布订阅还是不太适合商用,并不支持消息重试,即便重新注册上了,之前的消息也丢了。

Redis可能会阻塞的情况

如果一个值的size过大,写入时开辟内存以及发送时的数据 copy 开销都会很大。

建议从业务上对大key做拆分。

对于一些数据结构的操作,时间复杂度为 O(N) ,如果不加控制,可能会引起阻塞。

例如 Keys 命令,由于没有limit参数,会全表扫描,耗时大。可以考虑用Scan替代。

尽管使用了IO多路复用技术,读写 copy 以及 User Mode 和 Kernel Mode 的切换会比较耗时。

尽管 RDB 是fork后独立进程中完成落盘工作,fork 这个 System Call 本身耗时大概在700ms级别。

建议尽量避免在高峰时期执行 Save 或 Bgsave 命令。

由于AOF需要修改磁盘中的日志文件,修改文件及其iNode需要两次随机读写IO,大约耗时在20ms级别,因此业务中几乎不会开启 always 模式。

一般都用 Everysecond模式。

由于 Redis 的删除过期键策略中有一条是主动删除:会随机抽出100个设置了过期的key,对已过期的进行删除,如果发现过期的key超过25个,就会重复这个过程。因此,如果有大量同一时间过期的key,会在主动删除触发时,不停地取key删key,造成阻塞。

建议在设置过期时间时使用 Expire 而非 Expireat,或者使用 Expireat 时自己给入一个随机量,让过期时间离散开。

当 Redis 可支配的内存空间不足时,会进行内存逐出操作。尽管可以配置策略,但是逐出时CPU会hang住。

建议对内存使用情况做监控,及时扩容或进行其他人为介入操作。

赞(0)
文章名称:《redis订阅为什么阻塞(redis订阅发布缺点)》
文章链接:https://www.fzvps.com/247103.html
本站文章来源于互联网,如有侵权,请联系管理删除,本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。
图片版权归属各自创作者所有,图片水印出于防止被无耻之徒盗取劳动成果的目的。

评论 抢沙发

评论前必须登录!