Redis的发布订阅Topic模式

核心代码:

Springboot下的redis发布订阅topic模式,与Springboot的Event事件有异曲同工之妙,但是redis的发布订阅可以用于分布式系统,但是Event只能在同一个JVM实例起作用,同时要注意的是,因为redis是面向分布式系统设计的,因此有多个JVM实例都订阅了同一个Topic的话,会产生重复消费,因此如果不需要重复消费的场景,在消费的时候一定要在消费的时候进行幂等校验。Event使用的博客在SpringBoot Event 事件监听,这两种消息队列可靠性都不是很高,因为没有持久化及消费ACK确认机制,所以对可靠性高的系统,建议还是引入消息队列,关于消息队列的博客,可以参考我之前的笔记RabbitMQ实战指南之消息可靠性RabbitMQ实战指南之RabbitMQ架构及运转流程
主要有三步:

  1. 获取主题
  2. 主题添加订阅者
  3. 通过主题发布事件
RTopic<SomeObject> topic = redisson.getTopic("anyTopic");
topic.addListener(new MessageListener<SomeObject>() {
    @Override
    public void onMessage(String channel, SomeObject message) {
    //..
    .}
});
// in other thread or JVM
RTopic<SomeObject> topic = redisson.getTopic("anyTopic");
long clientsReceivedMessage = topic.publish(new SomeObject());

具体过程

订阅者实现

@Component
public class ProjectMessageRedisListener implements MessageListener<ContractPassedEvent> {
    public static final String TOPIC = "ContractPassedEvent";
    @Autowired
    RedissonClient redissonClient;

    @Override
    public void onMessage(CharSequence channel, ContractPassedEvent msg) {
        System.out.println("收到事件:" + msg);
    }
}


//必须实现序列化接口
@Data
public class ContractPassedEvent  implements Serializable {
    private static final long serialVersionUID = -1L;
    private String name;
}

注册订阅者

@Configuration
@EnableAsyncpublic 
class WebMvcConfigure implements WebMvcConfigurer {
@Autowired
RedissonClient redissonClient;

@Bean("contractPassedTopic")
public RTopic contractPassedTopic(){
    //注册监听
    RTopic topic = redissonClient.getTopic(ProjectMessageRedisListener.TOPIC);
    topic.addListener(ContractPassedEvent.class, projectMessageRedisListener);
    return topic;
}

发布事件

@RunWith(SpringRunner.class)
@SpringBootTest(classes = WebSpringBootTestApplication.class)
public class ProjectMessageRedisListenerTest{
    @Autowired
    RTopic topic;

    @Test
    public void testRedisTopic(){
        topic.publish(new ContractPassedEvent("A00-Nj-2021-01-289-002932"));
    }
}

订阅到多个主题

// subscribe to all topics by `topic1.*` pattern
RPatternTopic<Message> topic1 = redisson.getPatternTopic("topic1.*");
int listenerId = topic1.addListener(new PatternMessageListener<Message>() {
    @Override
    public void onMessage(String pattern, String channel, Message msg) {
        Assert.fail();
        }
});

原理

订阅:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r23NZCPp-1631711043925)(evernotecid://5017348F-AB9A-4431-A7FF-4D27C619FCD9/appyinxiangcom/31661346/ENResource/p281)]

发布:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFHuTq1r-1631711043927)(evernotecid://5017348F-AB9A-4431-A7FF-4D27C619FCD9/appyinxiangcom/31661346/ENResource/p282)]

Redis 发布订阅功能的特性

Topic 模式监听器在重连到 Redis 服务器或者 Redis 服务器故障恢复时自动重新订阅。

  1. 消息的发送者与接收者之间通过 channel 绑定:channel 可以是确定的字符串,也可以基于模式匹配
  2. 客户端可以订阅任意多个channel
  3. 发送者发送的消息无法持久化,所以可能会造成消息丢失
  4. 由于消息无法持久化,所以,消费者无法收到在订阅channel之前发送的消息
  5. 发送者与客户端之间的消息发送与接收不存在 ACK 机制

Redis 发布订阅功能的适用场景

由于没有消息持久化与 ACK 的保证,所以,Redis 的发布订阅功能并不可靠。这也就导致了它的应用场景很有限,建议用于实时与可靠性要求不高的场景。例如:
消息推送
内网环境的消息通知

猜你喜欢

转载自blog.csdn.net/crazyjack1/article/details/120317084