Redis 发布订阅模式完全指南
引言
在前面的 Redis 文章中,我们学习了五种基本数据类型、持久化、主从复制和哨兵模式。今天要讲的是 Redis 的发布订阅功能——一种轻量级的消息通信模式。
发布订阅的核心思想很简单:有人发布消息到频道,订阅了该频道的人就能收到消息。这和微信公众号非常像——你关注了一个公众号(订阅频道),号主发文章(发布消息),你就能收到推送。
虽然专业消息队列(如 RabbitMQ、Kafka)功能更强大,但 Redis 的发布订阅足够轻量、零配置,适合中小型项目中的实时通知、聊天消息等场景。
第一部分:基础命令
一、订阅频道
# 语法:SUBSCRIBE 频道名 [频道名 ...] # 订阅一个或多个频道 # 终端1:订阅 news 和 sports 频道 127.0.0.1:6379> SUBSCRIBE news sports Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "news" 3) (integer) 1 1) "subscribe" 2) "sports" 3) (integer) 2执行 SUBSCRIBE 后,客户端进入订阅模式,会一直阻塞等待消息,直到手动Ctrl+C退出。
二、发布消息
# 语法:PUBLISH 频道名 消息内容 # 终端2:向 news 频道发布消息 127.0.0.1:6379> PUBLISH news "今天科技圈发生了大事" (integer) 2 # 返回值 2 表示有 2 个订阅者收到了消息 # 向 sports 频道发布消息 127.0.0.1:6379> PUBLISH sports "CBA总决赛今晚打响" (integer) 2终端1 收到的消息:
为甚会出现这种\xe4此类信息呢,那他是错误的还是怎么回事???
原因:
其实收到\xe4\xbb...这样的数据,是因为Redis 客户端和服务器之间的编码/解码不一致。
简单说:Redis 存进去的是"好的"中文,但你用来显示的程序把它当成了"原始字节码"直接打印了。(所以他们其实是一个东西,只是展示的样子不同罢了,就像不同语言一样汉语与英语)
那么如何解决呢?
在进入 Redis 之前,先设置一下编码,或者在连接时指定:
# 方法1:设置终端编码 export LANG=zh_CN.UTF-8 redis-cli # 方法2:连接时加上 --raw 参数(推荐) redis-cli --raw加上--raw后,再XREAD或GET,应该就能直接显示中文了。
三、退订频道
# 语法:UNSUBSCRIBE [频道名 ...] # 不带参数则退订所有频道 127.0.0.1:6379> UNSUBSCRIBE news # 只退订 news 127.0.0.1:6379> UNSUBSCRIBE # 退订所有第二部分:模式订阅
除了订阅具体频道,Redis 还支持模式匹配——订阅所有名称匹配某种模式的频道。
# 语法:PSUBSCRIBE 模式 [模式 ...] # 订阅所有以 "news." 开头的频道 127.0.0.1:6379> PSUBSCRIBE news.*通配符规则:
| 模式 | 匹配 | 不匹配 |
|---|---|---|
news.* | news.sports、news.tech | news、sports.news |
news.*.china | news.tech.china、news.sports.china | news.china |
* | 所有频道 | — |
# 测试 # 终端1:模式订阅 127.0.0.1:6379> PSUBSCRIBE news.* # 终端2:发布消息 127.0.0.1:6379> PUBLISH news.tech "AI 新突破" (integer) 1 # 终端1 收到: 1) "pmessage" # 模式消息类型 2) "news.*" # 匹配的模式 3) "news.tech" # 实际频道名 4) "AI 新突破" # 消息内容普通订阅 vs 模式订阅:
| 订阅方式 | 命令 | 收到消息格式 | 用途 |
|---|---|---|---|
| 普通订阅 | SUBSCRIBE | message | 订阅具体频道 |
| 模式订阅 | PSUBSCRIBE | pmessage | 按模式匹配批量订阅 |
退订模式:
# 语法:PUNSUBSCRIBE [模式 ...] 127.0.0.1:6379> PUNSUBSCRIBE news.*第三部分:查看频道状态
# 查看当前活跃的频道(至少有一个订阅者) 127.0.0.1:6379> PUBSUB CHANNELS 1) "news" 2) "sports" # 查看匹配模式的活跃频道 127.0.0.1:6379> PUBSUB CHANNELS news.* 1) "news.tech" 2) "news.sports" # 查看某个频道的订阅者数量 127.0.0.1:6379> PUBSUB NUMSUB news sports 1) "news" 2) (integer) 3 # news 有 3 个订阅者 3) "sports" 4) (integer) 2 # sports 有 2 个订阅者 # 查看模式订阅的数量 127.0.0.1:6379> PUBSUB NUMPAT (integer) 2 # 当前有 2 个模式订阅第四部分:实际应用场景
一、实时聊天系统
# 用户A 发送消息 PUBLISH room_101 "大家好,我是新来的" # 用户B、C、D(都订阅了 room_101)立即收到二、系统通知推送
# 场景:电商系统,订单状态变更通知 # 用户下单后,订阅自己的订单频道 SUBSCRIBE order:10086 # 后台处理订单,状态变更时发布消息 PUBLISH order:10086 "您的订单已发货,快递单号:SF1234567890" # 用户收到实时通知三、配置热更新
第五部分:C 语言实现发布订阅
一、发布者
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <hiredis/hiredis.h> int main() { // 连接 Redis redisContext *c = redisConnect("127.0.0.1", 6379); if (c == NULL || c->err) { printf("连接失败: %s\n", c->errstr); return -1; } // 发布消息 redisReply *reply = redisCommand(c, "PUBLISH news %s", "Hello, Redis 发布订阅!"); if (reply == NULL) { printf("发布失败\n"); return -1; } printf("订阅者数量: %lld\n", reply->integer); freeReplyObject(reply); redisFree(c); return 0; }编译:
gcc publisher.c -o publisher -lhiredis
二、订阅者
#include <stdio.h> #include <stdlib.h> #include <hiredis/hiredis.h> int main() { redisContext *c = redisConnect("127.0.0.1", 6379); if (c == NULL || c->err) { printf("连接失败: %s\n", c->errstr); return -1; } // 订阅频道 redisReply *reply = redisCommand(c, "SUBSCRIBE news"); if (reply == NULL) { printf("订阅失败\n"); return -1; } freeReplyObject(reply); // 循环接收消息 printf("等待消息...\n"); while (redisGetReply(c, (void**)&reply) == REDIS_OK) { if (reply->type == REDIS_REPLY_ARRAY && reply->elements == 4) { // 收到消息:[message, 频道名, 消息内容, 空] printf("频道: %s\n", reply->element[1]->str); printf("内容: %s\n", reply->element[2]->str); } freeReplyObject(reply); } redisFree(c); return 0; }第六部分:发布订阅的局限性
| 缺点 | 说明 | 解决方案 |
|---|---|---|
| 消息不持久化 | 订阅者不在线时发的消息会丢失 | 改用 Redis Stream 或专业消息队列 |
| 无确认机制 | 发布者不知道消息是否被处理 | 改用 RabbitMQ(ACK 机制) |
| 无消息堆积 | 消息不会被存储,即发即忘 | 改用 Kafka(持久化消息) |
| 订阅者阻塞 | SUBSCRIBE 后客户端只能接收消息 | 需要专门的连接处理 |
什么时候用 Redis 发布订阅?
| 场景 | 是否适合 |
|---|---|
| 实时聊天 | ✅ 适合 |
| 系统通知 | ✅ 适合 |
| 配置热更新 | ✅ 适合 |
| 订单处理(不能丢消息) | ❌ 不适合 |
| 金融交易(需要确认) | ❌ 不适合 |
总结
一、核心命令速查
| 命令 | 作用 |
|---|---|
SUBSCRIBE channel | 订阅频道 |
UNSUBSCRIBE [channel] | 退订频道 |
PUBLISH channel msg | 发布消息 |
PSUBSCRIBE pattern | 模式订阅 |
PUNSUBSCRIBE [pattern] | 退订模式 |
PUBSUB CHANNELS | 查看活跃频道 |
PUBSUB NUMSUB | 查看订阅者数量 |
二、消息格式
| 订阅方式 | 消息格式 |
|---|---|
| 普通订阅 | [message, 频道名, 消息内容] |
| 模式订阅 | [pmessage, 模式, 频道名, 消息内容] |
三、一句话记忆
Redis 发布订阅是一种轻量级消息通信模式,发布者通过 PUBLISH 向频道发消息,订阅者通过 SUBSCRIBE 实时接收。支持通配符模式匹配(PSUBSCRIBE),但不持久化、不确认,适合实时通知等场景,不适合关键业务消息。
