Springboot+Redis- 实现发布订阅

1.发布订阅原理分析

1.1发布订阅模式

        在软件架构中,发布/订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者),而是通过消息通道广播出去,让订阅改消息主题的订阅者消费到。发布/订阅者模式最大的特点就是实现了松耦合,也就是说你可以让发布者发布消息、订阅者接受消息,而不是寻找一种方式把两个分离的系统连接在一起。当然这种松耦合也是发布/订阅者模式最大的缺点,因为需要中间的代理,增加了系统的复杂度。而且发布者无法实时知道发布的消息是否被每个订阅者接收到了,增加了系统的不确定性。

1.2发布/订阅者模式的优点

   发布/订阅者模式的优点可以归纳为:

        1)松耦合/Independence

   发布/订阅者模式可以将众多需要通信的子系统(Subsystem)解耦,每个子系统都可以独立管理。而且即使部分子系统下线了,也不会影响系统消息的整体管理。发布/订阅者模式为应用程序提供了关注点分离。每个应用程序都可以专注于其核心功能,而消息传递基础结构负责将消息路由到每个消费者手里。

      2)高伸缩性/Scalability

发布/订阅者模式增加了系统的可伸缩性,并提高了发送者的响应能力。原因是发送方(Publisher)可以快速地向输入通道发送一条消息,然后返回到其核心处理职责,而不必等待子系统处理完成。然后消息传递的基础结构负责确保把消息传递到每个订阅者(Subscriber)手里。

       3)高可靠性/Reliability

   发布/订阅者模式提高了可靠性。异步的消息传递有助于应用程序在增加的负载下继续平稳运行,并且可以更有效地处理间歇性故障。

       4)灵活性/Flexibility

你不需要关心不同的组件是如何组合在一起的,只要他们共同遵守一份协议即可。发布/订阅者模式允许延迟处理或者按计划的处理。例如当系统负载大的时候,订阅者可以等到非高峰时间才接收消息,或者根据特定的计划处理消息。

        5)可测试性/Testability

发布/订阅者模式提高了可测试性。通道可以被监视,消息可以作为整体集成测试策略的一部分而被检查或记录。

1.3Redis发布订阅底层实现原理

使用SUBSCRIBE [频道名]即可订阅特定频道,频道名可以自定义,也可以同时订阅多个频道,只需要后面添加多个频道名即可

127.0.0.1:6379> SUBSCRIBE "news.redis"  //订阅"news.redis"频道
Reading messages... (press Ctrl-C to quit)
1) "subscribe"  //命令关键字
2) "news.redis" //频道名
3) (integer) 1  //订阅该频道的客户端数量

使用PUBLISH [频道名] [消息]即可向特定频道发送消息

127.0.0.1:6379> PUBLISH "news.redis" "send a message"   //向"news.redis"频道发送消息
(integer) 1 //返回发送给了多少个客户端
127.0.0.1:6379> 

此时,如果再查看订阅news.redis频道的那个客户端,会发现终端上打印出”send a message”信息

//PUBLISH之前
127.0.0.1:6379> SUBSCRIBE "news.redis"
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "news.redis"
3) (integer) 1

//PUBLISH之后
1) "message"    //消息类型
2) "news.redis" //频道名
3) "send a message" //信息
 

1.3.1数据结构说明

     

在深入源代码之前,先看两个结构的定义,一个是客户端,一个是服务器,它们都定义在server.h头文件中

//server.h
typedef struct client {
    ...
    dict *pubsub_channels; 
    ...
} client;
 
//server.h
struct redisServer {
    ...
    dict *pubsub_channels;  
    ...
};

   重点看pubsub_channels变量,根据类型得知该变量是一个字典(以下简称为订阅字典),两个变量的作用分别是

  • 客户端的订阅字典记录着当前客户端订阅的所有频道,键是频道名,值为空
  • 服务器的订阅字典记录着所有频道以及每个频道的订阅者,键是频道名,值是客户端链表

       到这里其实可以简单猜测订阅功能是如何实现的,当某个客户端使用SUBSCRIBE命令订阅一个或多个频道时,Redis会将<频道名,客户端>这个键值对添加到服务器的订阅字典中,同时也会将频道名添加到客户端自己的订阅字典中。而当客户端使用PUBLISH命令向某个频道发送消息时,Redis会在订阅字典中获取该频道的所有订阅者(客户端),依次将消息发送给客户端。如果该频道不存在或没有订阅者,则不执行任何操作。

订阅功能
订阅功能由subscribeCommand函数完成,函数主要任务是遍历每一参数(频道名),调用pubsubSubscribeChannel函数将频道名和客户端添加到订阅字典中

//pubsub.c
/* 订阅命令 */
void subscribeCommand(client *c) {
    int j;

    /* 将客户端和它订阅的频道进行关联,添加到订阅字典中
     * 键是频道名,值是客户端 
     */
    for (j = 1; j < c->argc; j++)
        pubsubSubscribeChannel(c,c->argv[j]);
    /* 标记当前客户端订阅过某些频道 */
    c->flags |= CLIENT_PUBSUB;
}

pubsubSubscribeChannel函数完成实际的添加操作

//pubsub.c
/* 
 * 将客户端和它订阅的频道进行关联,添加到客户端和服务器两个订阅字典中 
 * 
 * 注:服务器和客户端都有订阅字典,分别是
 * c->pubsub_channels
 * server.pubsub_channels
 */
int pubsubSubscribeChannel(client *c, robj *channel) {
    dictEntry *de;
    list *clients = NULL;
    int retval =

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值