Redis 发布订阅(长文解析)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在分布式系统开发中,消息通信是核心需求之一。无论是构建实时聊天室、推送通知系统,还是实现事件驱动架构,开发者都需要一种高效且灵活的消息传递机制。Redis 的发布订阅(Publish/Subscribe)功能,正是为此类场景设计的轻量级解决方案。它通过“发布-订阅”模式,让消息生产者与消费者之间无需直接耦合,即可实现异步通信。本文将从基础概念到实战案例,深入解析 Redis 发布订阅的原理与应用,并通过代码示例帮助读者快速上手。


核心概念:什么是 Redis 发布订阅?

Redis 的发布订阅是一种基于消息的通信模式,其核心思想是**“一对多”消息分发**。具体来说,它包含以下两个角色:

  1. 发布者(Publisher):负责向特定频道(Channel)发送消息。
  2. 订阅者(Subscriber):监听一个或多个频道,接收并处理频道中的消息。

这种模式可以类比为广播电台系统

  • 发布者就像电台,向特定频率(频道)发送节目内容(消息);
  • 订阅者如同收音机,调频到对应频道后,即可接收节目内容。

关键术语解析

术语解释
Channel消息分发的逻辑通道,每个频道对应一组订阅者
Message发布者发送的具体数据,可以是文本、JSON 或二进制格式
Pattern通配符订阅模式,允许订阅者匹配多个符合规则的频道

工作原理:消息如何在 Redis 中流动?

Redis 发布订阅的实现基于其内存数据库特性,消息传递过程分为三个阶段:

1. 订阅阶段

订阅者通过 SUBSCRIBEPSUBSCRIBE 命令,向 Redis 服务器注册需要监听的频道或模式。此时,Redis 会维护一个频道-订阅者映射表,记录每个频道对应的活跃订阅者列表。

2. 发布阶段

发布者调用 PUBLISH 命令,将消息发送到指定频道。Redis 会立即检查该频道的订阅者列表,并将消息推送到所有订阅者的输出缓冲区中。

3. 消息消费阶段

订阅者通过持续监听 Redis 的响应流,获取并处理接收到的消息。

比喻:快递分拣系统

想象一个快递分拣中心:

  • 频道 = 快递柜的不同格口;
  • 发布者 = 分拣员将包裹投入对应格口;
  • 订阅者 = 快递员在格口前等待取件。

当分拣员(发布者)将包裹(消息)放入格口(频道)后,所有在该格口前等待的快递员(订阅者)都能即时获取包裹。


核心命令详解

Redis 发布订阅的核心命令包括:

1. SUBSCRIBE channel [channel ...]

  • 作用:订阅一个或多个指定频道。
  • 示例
    SUBSCRIBE chat_room notifications  
    
  • 响应:订阅成功后,客户端进入订阅模式,后续只能执行与订阅相关的命令。

2. PUBLISH channel message

  • 作用:向指定频道发布消息。
  • 示例
    PUBLISH chat_room "Hello everyone!"  
    
  • 返回值:收到消息的订阅者数量。

3. UNSUBSCRIBE [channel [channel ...]]

  • 作用:取消对指定频道的订阅,或取消所有订阅。
  • 示例
    UNSUBSCRIBE chat_room  
    

4. PSUBSCRIBE pattern [pattern ...]

  • 作用:通过模式(如 chat_*)订阅符合规则的频道。
  • 示例
    PSUBSCRIBE "user_*"  
    
  • 匹配规则* 表示匹配任意字符,? 匹配单个字符。

实战案例:搭建实时聊天室

以下通过 Python 示例,演示如何使用 Redis 发布订阅实现一个简单的多人聊天室:

步骤 1:安装 Redis 客户端

pip install redis  

步骤 2:编写订阅端代码

import redis  
import time  

client = redis.Redis(host='localhost', port=6379, db=0)  

def subscribe_messages():  
    pubsub = client.pubsub()  
    pubsub.subscribe('chat_room')  # 订阅频道  

    for message in pubsub.listen():  
        if message['type'] == 'message':  
            print(f"收到消息: {message['data'].decode()}")  

if __name__ == "__main__":  
    subscribe_messages()  

步骤 3:编写发布端代码

import redis  

client = redis.Redis(host='localhost', port=6379, db=0)  

def send_message(message):  
    client.publish('chat_room', message.encode())  

if __name__ == "__main__":  
    while True:  
        text = input("请输入消息(输入 'exit' 退出): ")  
        if text == 'exit':  
            break  
        send_message(text)  

运行效果

  1. 启动多个订阅端实例,模拟多个用户;
  2. 在发布端输入消息,所有订阅端将实时收到消息。

进阶技巧与注意事项

1. 消息丢失问题

Redis 发布订阅是非持久化的,若订阅者在消息发布时未处于活跃状态,将无法接收到消息。为解决此问题,可结合以下方案:

  • 持久化存储:将消息存入 Redis 列表或 Stream 数据结构,订阅者主动拉取。
  • 队列系统:与 RabbitMQ 或 Kafka 结合,实现消息持久化和可靠投递。

2. 性能优化

  • 批量发布:使用 pipeline 批量发送消息,减少网络开销。
  • 频道命名规范:避免使用过长或动态生成的频道名,减少 Redis 内存占用。

3. 网络分区场景

在分布式环境下,若 Redis 集群出现网络分区,订阅者可能因连接中断而丢失消息。可通过以下方式缓解:

  • 心跳检测:定期检查与 Redis 的连接状态,及时重连。
  • 持久化订阅:使用 redis-pyreconnect 参数实现自动重连。

应用场景与扩展思考

典型场景

  1. 实时通知系统:如社交媒体的点赞、评论提醒。
  2. 事件驱动架构:微服务间解耦的事件分发。
  3. 监控告警:实时推送系统指标异常通知。

与其他消息中间件的对比

特性Redis 发布订阅RabbitMQ/Kafka
持久化支持不支持(默认)支持
消息可靠性最佳努力交付有保障
复杂路由能力简单频道匹配支持高级路由规则
性能极高(内存级)较高(依赖网络)

结论

Redis 发布订阅凭借其轻量、高效和易用的特点,成为构建实时通信系统的理想选择。通过本文的讲解,读者可以掌握其核心原理、命令用法及常见问题的解决方案。在实际开发中,开发者需结合业务需求,合理选择与持久化存储或消息队列的结合方式,以满足不同场景下的可靠性与性能要求。

掌握这一技术后,读者可尝试将其应用于实时聊天、物联网设备通信等场景,进一步探索 Redis 在分布式系统中的强大能力。

最新发布