前言
项目中经常使用到本地缓存,那么在集群模式下如何能够保证多实例缓存刷新呢?一般我们会采用redis 的订阅发布模式,但是原生的订阅发布模式有一个弊端,就是当一个业务实例发布了一个刷新缓存的消息,订阅者假如遇到网络波动等原因可能会接收不到,因此redisson提供了一种可靠的订阅发布实现(RReliableTopic)相对于原生的订阅发布(RTopic)其增加了记录订阅者的功能。
RReliableTopic实现原理
RReliableTopic底层采用Stream实现了一个队列,发布者投递消息到队列后,每一个订阅者都做为一个独立的消费者组来消费队列消息,这样一来如果某个订阅者(业务实例)实例发生网络波动或者重启等操作后,消息仍然可以被消费到,但是Stream本身不能感知到消费者组是否已经永久下线,因此需要一套机制来记录消费者组在线状态。因此redisson在Stream的基础上新增了Zset结构的集合来存放消费者组实例信息以及其下线时间。订阅者在初次订阅时redisson会默认该实例在10分钟后下线,但是这个时间并不是准确的,因此redisson会使用watchdog技术实时的去延长该下线时间。当订阅者永久下线后,zset中的过期时间到期时,redisson会移除Stream中的消费者组,这样Stream的消费进度会向前推进,已经被完全消费过的消息就能够清理,不再占用redis内存。
问题出现在了哪里?
发现测试环境redis中存在一个zset结构没有过期时间的key, 且数据长时间滞留,通过排查发现是redisson创建的数据结构,通过阅读代码发现问题:redisson在清理Stream中的消费者组后,并没有把zset结构中的实例信息删除,导致数据长时间滞留内存持续膨胀。
解决方法:
在清理消费者组后及时清理zset.