`
OrangeHolic
  • 浏览: 260730 次
  • 来自: 北京
社区版块
存档分类
最新评论

Redis - PubSub(发布者-订阅者模式)的内部实现

 
阅读更多
一.设计模式-发布订阅模式

发布订阅模式,又叫观察者模式,属于四人帮的二十三个设计模式中的行为模式。”定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于他的对象都会得到通知并被自动更新“,模式UML如下图。

通俗一点可以理解为,Subject中保存了Observer的引用组成的列表。Subject状态变化时,遍历列表调用所有Observer的notify成员方法。
发布订阅模式应用场景很多,相当于在系统中构建一个简单的事件处理系统,部分编程语言(如java提供被观察者类java.util.Observable和观察者接口java.util.Observer)原生库中已包含观察者模式的简单实现。

二.Redis-PubSub介绍

Redis中的PubSub实现较上面复杂,但设计思想和上面一致。

客户端A发出一个订阅的频道名称(可以理解为attach A 到Subject)
subscribe  temperature  rainfall


其他客户端B发布消息(可以理解为B更新Subjec的状态)
publish  rainfall 350cc


A客户端将收到降雨量350cc这条message

客户端A也可以取消订阅频道(可以理解为A从Subjec中detach)
unsubscribe rainfall




在提供订阅频道外,Redis还提供了psubscribe/punsubscribe来订阅/取消订阅一个或多个模式。如果模式照通配符(glob)来匹配某个/ 某些频道,当有信息发送给这个/这些频道的时候, 客户端也会收到这个/这些频道的信息。

二.Redis-PubSub订阅频道


Redis中PubSub实现也比较简单,订阅频道的功能主要保存在字典中,其中key为频道,而value是redisClient组成的列表。

下图为订阅频道的redisServer的pubsub_channels字典示例,ClientA订阅 temperature和rainfall,ClientC订阅temperature



当客户端ClientD订阅已经存在的频道时,将ClientD加到该频道对应的链表的尾巴,如订阅rainfall频道。
当客户端ClientD订阅不存在的频道时,新建新频道的key及对应的链表,将ClientD加到新创建的链表中,下图为ClientD执行 subscribe snow后的字典示例。



当客户端ClientA取消订阅频道时,将客户端ClientA从对应的频道的链表中删除,如果删除后对应的频道无客户订阅,则将对应的频道的key从字典中删除。
如ClientA执行subscribe(无参数的subscribe 命令订阅的所有频道都会被退订)后字典的示例。



以上的所有操作在更新redisServer的pubsub_channels字典的同时也会更新redisClient中的pubsub_channels字典,redisClient的pubsub_channels保存着对应客户端订阅的频道。


四.Redis-PubSub订阅模式

订阅模式的功能保存在redisServer的pubsub_patterns链表中,链表的元素结构如下:

typedef struct pubsubPattern {
   /*客户端信息,唯一确认一个客户连接*/
    redisClient *client;
   /*模式信息的字符串对象,如"*no*"*/
    robj *pattern;
} pubsubPattern;

下图示例客户端ClientA 订阅“*it*”、"*eye*",客户端ClientB订阅"*eye*"的链表。



增加时遍历redisClient的pubsub_patterns链表,如果不存在,将新的模式增加到redisServer的pubsub_patterns链表的尾部。

删除时需要遍历redisClient的整个pubsub_patterns,如果存在,在定位redisServer的pubsub_patterns链表进行删除操作。

与订阅频道同样,在更新redisServer的pubsub_patterns链表的同时,也更新redisClient的pubsub_patterns链表,redisClient的pubsub_channels保存着对应客户端订阅的模式。

五.消息发送publish

当发送消息时,先从redisServer找到对应的频道的key所拥有的链表,遍历链表发送消息;然后遍历redisServer的pubsub_patterns链表,对频道和pattern进行匹配(stringmatch),如果适配将信息增加到客户端的返回中。
发送消息的伪代码如下:
/*
* 发送消息
* channel 频道
* message  消息主体
* */
function pubsubPublishMessage(channel,message){

    /*需要channel被某些客户端订阅,如果不存在pubsub_channels中,就没有订阅此频道的客户*/
    if (isset(server.pubsub_channels[channel])){
        /*
         * 遍历pubsub_channels中对应频道的订阅者的链表
         * 给每个频道订阅者发布消息
         * */
        foreach (server.pubsub_channels[channel] as receiver){

            sendMessage(receiver, message);
        }

    }
    /*遍历模式订阅的链表*/
   foreach (server . pubsub_patterns as pubsubPattern){

        /*如果模式与频道适配,发送消息给此客户端*/
        if (stringmatch(pubsubPattern.pattern, channel)) {

            sendMessage(pubsubPattern.client, message);

        }

    }

}



从上面代码中可以Redis发布的消息“即发即失”,redis不会持久保存发布的消息, 一旦client端断开链接,将会失去部分消息。
如果需要client非常关注的消息(如用户支付订单成功,client发货),建议不要用Redis的PubSub功能,可以用其他专门的消息队列系统,也可用Redis的链表,然后客户端进行轮询。

  • 大小: 28.3 KB
  • 大小: 28.3 KB
  • 大小: 10.3 KB
  • 大小: 15.9 KB
  • 大小: 13.5 KB
  • 大小: 8.4 KB
  • 大小: 26.5 KB
分享到:
评论

相关推荐

    redis-py-master.zip

    - 使用`pubsub()`创建订阅者对象,`subscribe()`订阅频道,`publish()`向频道发送消息。 - 示例:`pubsub = r.pubsub()`,`pubsub.subscribe('channel')`,`r.publish('channel', 'message')` 9. **脚本(Lua ...

    go-redis-pubsub-example

    在这个项目中,你可能会看到如何初始化Redis客户端,创建订阅者来监听特定频道,以及发布者如何向这些频道发送消息的代码。这将涉及到`redis.NewClient()`来创建客户端,`client.PubSub()`获取Pub/Sub接口,`pubsub...

    使用Redis的pubsub技术构建实时消息系统

    Redis是一种高性能的键值数据库,特别适合用于构建实时消息系统,因为它的发布/订阅(pub/sub)模式可以实现实时数据传输。在这个系统中,发布者(pub)发送消息到特定的主题(channel),而订阅者(sub)可以监听并...

    redis-pubsub-demo:Spring Boot和Redis PubSub的演示项目

    Redis Pub/Sub(发布/订阅)是Redis数据库系统中的一个重要特性,它允许客户端订阅特定的通道(channels),然后发布者可以通过这些通道向订阅者发送消息。在这个"redis-pubsub-demo"项目中,我们将深入探讨如何在...

    Laravel开发-lumen-pubsub

    4. **容错性**:即使某些订阅者失败,其他订阅者仍能继续工作。 常见应用场景包括用户行为跟踪、订单处理、实时通知、日志记录等。 总结,Lumen 的 Pub/Sub 能力使得开发者能够在微服务架构中实现灵活且可靠的通信...

    koa-pubsub-ws:koa-pubsub-ws

    在这个模式中,服务器作为发布者,可以广播消息给多个订阅者,即客户端。每个订阅者都可以选择接收特定类型的消息,这样就实现了广播和定向推送的灵活组合。此外,Koa-PubSub-WS还提供了错误处理和连接管理的功能,...

    Go-redis-Golang的类型安全Redis客户端

    Go-redis还支持Redis的发布/订阅功能,允许你创建订阅者来监听特定频道的消息。 ```go pubsub := rdb.PubSub() err := pubsub.Subscribe(context.Background(), "channel") if err != nil { panic(err) } // 在另...

    redis-pubsub

    1. Redis Pub/Sub不提供历史消息存储,订阅者只能接收订阅后发布的消息。 2. 发布者和订阅者之间没有确认机制,消息一旦发布就立即消失,无法保证消息是否被所有订阅者接收到。 3. 为了提高健壮性,可以考虑结合其他...

    Redis中使用Java代码的方式实现发布订阅流程-发布者示例代码.zip

    在Redis中,发布/订阅(Publish/Subscribe,简称Pub/Sub)是一种消息通信模式,它允许消息生产者(发布者)发送消息到一个频道,而多个消息消费者(订阅者)可以实时接收这些消息。这个功能在分布式系统中尤其有用,...

    基于netcore 3.0的redis发布订阅示例代码

    以下是一个简单的.NET Core 3.0应用,展示了如何使用StackExchange.Redis创建发布者和订阅者。 1. 创建发布者(Publisher) ```csharp using StackExchange.Redis; using System; class Program { static void ...

    xk6-pubsub

    【xk6-pubsub】是一个基于Go语言的扩展库,专为K6性能测试工具设计,用于实现发布/订阅(Pub/Sub)模式的数据通信。K6是一款开源的负载测试工具,采用Go编写,用于模拟高并发用户负载,评估系统的性能和稳定性。而xk...

    redis-1.2.6:redis-1.2.6源码分析

    最后,Redis的发布订阅功能允许客户端订阅感兴趣的主题,当有其他客户端发布消息到该主题时,订阅者会收到通知。这一功能在`pubsub.c`中实现。 综上所述,"redis-1.2.6:redis-1.2.6源码分析"涵盖了Redis的基本数据...

    Pangaea-pubsub

    在软件设计中,发布/订阅是一种通信模式,其中生产者(发布者)发布事件,而消费者(订阅者)通过订阅这些事件来接收数据。这种模式允许解耦的组件之间进行通信,使得系统更具扩展性和灵活性。 Pangaea-pubsub 实现...

    node-red-contrib-redis:Redis的Node Red客户端,具有pubsub,list,lua脚本和其他命令

    节点红色贡献redis Redis的Node Red客户端,具有发布/订阅,列表,lua脚本,ssl,群集,自定义命令,实例注入和其他命令支持。 连接选项参数接收IORedis对象或字符串( )。 现在,每个配置名称使用相同的连接,如果...

    go-redis-demo:go-redis原始码分析

    除此之外,go-redis还实现了Pub/Sub功能,允许订阅和发布消息。`pubsub`包中的`PubSub`结构体提供了订阅和取消订阅的接口,以及接收消息的方法。这对于构建实时系统,尤其是消息队列场景,有着显著的价值。 在go-...

    express-todo-redis:带有Redis自定义pubsub实现的Todo应用示例express.js

    4. **Pub/Sub (发布/订阅)**: Redis的发布/订阅模型允许客户端(订阅者)订阅特定的频道,当有其他客户端(发布者)向该频道发送消息时,订阅者会接收到这些消息。 在"express-todo-redis"项目中,我们将实现以下...

    Predis一个PHP和HHVM功能完整的Redis客户端库

    5. **事务与发布/订阅**:支持Redis的事务机制和发布/订阅模式,实现复杂的业务逻辑。 6. **持久化策略**:允许配置不同的持久化策略,如RDB和AOF,以保证数据安全。 7. **命令响应式编程**:Predis提供了基于...

    Redis发布订阅和实现.NET客户端详解

    6. `PUBSUB`:获取有关订阅和发布系统的状态信息,如订阅者数量、频道等。 例如,一个简单的场景是,两个客户端订阅`order.create`频道,当第三个客户端发布一条消息到`order.create`时,前两个客户端将收到这条...

    redis技术文档

    Redis还支持发布订阅模式,可以实现消息的传递。在Python中,你可以创建一个发布者发布消息: ```python pubsub = r.pubsub() pubsub.subscribe('channel') r.publish('channel', 'message') ``` 而订阅者则可以监听...

    微服务SpringBoot整合Redis基于Redis的Stream消息队列实现异步秒杀下单

    Redis的发布订阅模型(PubSub)允许生产者向特定频道发布消息,所有订阅该频道的消费者都能接收到。这种模型支持多生产者和多消费者,但不支持数据持久化,且无法避免消息丢失,同时消息堆积有限制。 四、基于Redis...

Global site tag (gtag.js) - Google Analytics