PSUBSCRIBE仅支持glob模式(、?)匹配,不支持正则、动态路由或层级解析;需靠命名约定(如service.order.created)与多模式组合(如PSUBSCRIBE service.. service.order.)模拟多级订阅,但匹配在服务端逐个进行,性能随pattern数量线性下降。

PSUBSCRIBE 本身不支持动态路由,只做 glob 模式匹配
Redis 的 PSUBSCRIBE 不是消息路由器,也不解析业务语义;它只是对每个 PUBLISH 的 channel 字符串,挨个比对所有已注册的 glob 模式(* 和 ?),命中即推。所谓“动态路由”,其实是靠 channel 命名约定 + 模式设计模拟出来的。
常见误操作:
- 写
PSUBSCRIBE order.*.created却发PUBLISH order:123:created "msg"→ 冒号:不等于点.,完全不匹配 - 以为
PSUBSCRIBE *.order能捕获payment.order和user.order→ 可以,但性能差(* 开头需全量扫描) - 在同一个连接里先
SUBSCRIBE logs再PSUBSCRIBE logs.*→ Redis 直接拒绝,报错ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed
通配符怎么写才真正匹配多级结构
Redis 没有原生层级概念,“多级”全靠命名分隔符(推荐用 .,慎用 : 或 /)和模式组合。例如想匹配 service.order.created、service.payment.failed,可这样设计:
-
PSUBSCRIBE service.*.*→ 匹配两级子段,但会漏掉service.health(只有一级) -
PSUBSCRIBE service.order.*→ 精准捕获订单相关事件,不干扰 payment -
PSUBSCRIBE service.*.failed→ 只收失败类事件,不管哪个服务模块
注意:* 不匹配空字符,service.* 不会匹配 service 本身;? 必须对应一个真实字符,service.??.created 不会匹配 service.ai.created(因为 ai 是两个字符)。
多个模式怎么一起订阅,避免漏消息
PSUBSCRIBE 支持一次传多个 pattern,用空格分隔(不是逗号,也不是引号包裹):
PSUBSCRIBE service.order.* service.payment.* service.user.*
这等价于三个独立订阅,各自独立匹配。但要注意:
- 每个 pattern 都会增加服务端匹配开销,100 个 client × 平均 5 个 pattern = 每次
PUBLISH触发 500 次 glob 判断 - 不同 pattern 之间无逻辑关系(不支持 AND/OR/NOT),不能写成
service.(order|payment).*—— 这是正则,Redis 不认 - Python 的
redis-py中调用pubsub.psubscribe("service.order.*", "service.payment.*")是安全的,底层自动拼命令
为什么 pattern 写对了却收不到消息?重点排查这三点
最常被忽略的不是语法,而是运行时上下文:
- Redis 配置开了
pubsub-nopatterns yes(某些云厂商默认启用)→PSUBSCRIBE直接返回ERR operation not permitted,但客户端可能静默吞掉错误 - 客户端连接没走 pub/sub 专用通道:Lettuce 必须用
redisClient.connectPubSub(),Spring 的RedisMessageListenerContainer要确认setTopicSerializer已设或 pattern 是String类型,否则PatternTopic注册失败且无日志 - channel 名大小写敏感:你
PSUBSCRIBE user.*,但发布方写了PUBLISH User.login "ok"→ 不匹配(User≠user)
上线前务必用 redis-cli 手动验证:开两个窗口,一个 PSUBSCRIBE user.*,另一个 PUBLISH user:123 login,看是否收到。别依赖客户端日志——它可能连连接都没建成功。



















