Redis发布订阅功能详解

Redis的发布订阅(Pub/Sub)功能提供了一种消息队列的实现方式,可以让发送方(发布者)向一个频道发布消息,订阅方(订阅者)则可以订阅相关频道接收消息。

1.发布订阅基本概念

发布订阅模式通过频道(channel)来实现消息的分发。发布者(publisher)可以向频道发布消息,订阅者(subscriber)可以订阅频道来接收消息。这种模式可以实现消息的异步传输。

在Redis中,客户端可以订阅任意数量的频道。当向被订阅的频道发布消息时,所有订阅该频道的客户端都会收到这条消息。

2.相关命令

SUBSCRIBE命令 – 订阅频道

SUBSCRIBE 命令用来订阅给定的一个或多个频道。语法如下:

SUBSCRIBE channel [channel ...]

例如:

SUBSCRIBE news.china news.world

这将订阅 news.china 和 news.world 两个频道。

UNSUBSCRIBE命令 – 取消订阅

UNSUBSCRIBE 命令用来取消对给定频道的订阅。语法如下:

UNSUBSCRIBE [channel [channel ...]]

例如:

UNSUBSCRIBE news.china

这将取消对 news.china 频道的订阅。

PSUBSCRIBE命令 – 使用模式订阅

PSUBSCRIBE 命令用于使用给定的模式订阅频道。语法如下:

PSUBSCRIBE pattern [pattern ...]

例如:

PSUBSCRIBE news.*

这将订阅所有以 news. 开头的频道。

PUNSUBSCRIBE命令 – 取消按模式的订阅

PUNSUBSCRIBE 命令用于取消给定模式的订阅。语法如下:

PUNSUBSCRIBE [pattern [pattern ...]]

PUBLISH命令 – 发布消息

PUBLISH 命令用于向给定的频道发布消息。语法如下:

PUBLISH channel message

例如:

PUBLISH news.china "新消息"

这将向 news.china 频道发布消息”新消息”。

go-redis 实现订阅发布

package main

import (
    "fmt"
    "time"
    "Github.com/go-redis/redis"
)

func subscriber(client *redis.Client) {
    pubsub := client.Subscribe("mychannel")
    // 使用模式订阅
    // pubsub := client.PSubscribe(ctx, "mychannel*")
    defer pubsub.Close()

    // 处理订阅接收到的消息
    for {
        msg, err := pubsub.ReceiveMessage()
        if err != nil {
            return
        }

        fmt.Println(msg.Channel, msg.Payload)
    }
}

func publisher(client *redis.Client) {
    for {
        // 发布消息到频道
        err := client.Publish("mychannel""hello").Err()
        if err != nil {
            panic(err)
        }
        time.Sleep(1 * time.Second)
    }
}

func main() {
    client := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })

    go subscriber(client)
    go publisher(client)

    <-make(chan struct{})
}

3. 使用场景

构建即时消息系统

可以通过发布订阅实现一个简单的聊天室。将每个聊天频道设为一个频道,用户发送消息就是向该频道发布消息,其他订阅了该频道的用户就可以收到消息。

异步任务处理

可以用来实现任务队列,通过发布消息将任务信息放到队列中,工作进程订阅频道获取任务并异步执行。

跨系统消息通知

例如订单系统完成下单后,可以发布一个消息到订单频道,物流系统订阅该频道获取订单信息来安排发货。

数据流处理

可以将实时产生的数据发布到频道中,数据处理程序订阅该频道获取流数据进行处理。比如接收实时的股票价格,进行处理后写入数据库。

4. 实现机制简介

普通模式

Redis发布订阅的实现机制主要涉及两个数据结构:

频道(channel)
频道是发布订阅的信息传递通道。每个频道都会维护一个订阅者链表,链表中存放了所有订阅这个频道的客户端。

订阅者(subscriber)
订阅者表示订阅了某些频道的客户端。每个客户端通过hash(dict)维护了订阅的所有频道。

当有新消息通过PUBLISH发布到某个频道时,Redis服务器会遍历这个频道对应的订阅者链表,将消息发布给每个订阅者客户端。
通过这个发布-订阅链表结构,Redis可以高效地实现频道订阅与消息发布分发的功能。这种机制使得频道与订阅者完全解耦,提高了Redis发布订阅功能的扩展性和性能。

pattern 模式

模式表(pubsub_patterns)
Redis用一个哈希表保存所有当前的订阅模式,哈希表的键就是模式,值是订阅这个模式的所有客户端列表。

客户端模式结构(client->pubsub_patterns)
客户端结构中也保存着这个客户端所有订阅的模式,用于快速判断一个消息的频道是否匹配了客户端的模式。

当一个频道发布新消息时,Redis会遍历模式表,检查是否有模式与这个频道匹配,如果匹配,就将消息发送给对应模式的客户端。
这样通过引入模式,可以实现更加灵活的订阅,如”news.*”可以订阅所有news相关的频道。

5. 最佳实践

使用注意事项

  1. 避免频道数量太多,可能导致内存占用过高

  2. 合理设置订阅的模式,避免匹配太广泛

  3. 设置消息过期时间,避免积压太多消息

  4. 不要依赖订阅者实时接收消息,发布订阅是异步的

常见问题及解决

  1. 消息积压:设置消息过期时间,并监控频道积压情况

  2. 消息丢失:确保订阅者及时读取消息,避免频道填满导致丢消息

  3. 客户端误订阅:每个订阅者指定订阅的频道,不使用无意义的通配符

  4. 消息重复:服务端去重,或由消费端幂等消费

  5. 订阅阻塞:确保消息能够正常消费,监控订阅者状态


此外,还要充分考虑发布订阅的异步性,不能简单地当作同步的远程调用使用。

原文始发于微信公众号(吃瓜技术派):Redis发布订阅功能详解

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/236061.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!