Pub/Sub 消息
SUBSCRIBE/PUBLISH、与 List 队列对比。
Pub/Sub 消息:判题完成的实时广播
这一课你将能做到
- 使用订阅、发布、模式订阅完成一条消息的实时广播
- 为本站设计「判题完成 → 网页实时弹出结果」的通知链路
- 说清楚 Pub/Sub 与 Stream、List 在消息可靠性上的根本差异
为什么要学
用户在题库提交代码后,页面会进入「判题中……」状态。判题可能要几秒到几十秒,前端怎么知道判完了?两种笨办法:页面每隔 1 秒问一次服务器「好了没」(轮询,浪费请求),或者一直傻等。
更优雅的方式是发布/订阅(Publish/Subscribe):判题服务完成后往一个频道(channel)「喊一嗓子」,所有订阅了这个频道的连接立刻收到消息,网页瞬间更新。它特别适合「一对多、瞬时、不需要留存」的实时通知。
先建立图像
发布者 PUBLISH judge:result "{...}"
│
┌───────────┼───────────┐
▼ ▼ ▼
订阅者A 订阅者B 订阅者C ← 同一条消息,人人有份
(用户1001 (数据统计 (管理员
的网页) 服务) 控制台)
关键:消息「发完即散」。发布那一刻没人订阅,消息就直接消失,
Redis 不会帮你存——这是和 Stream 最大的不同。
跟着做
步骤 1:订阅频道
终端 A(代表用户 1001 的网页服务端连接):
127.0.0.1:6379> SUBSCRIBE judge:result:1001
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "judge:result:1001"
3) (integer) 1
订阅后该连接进入订阅模式,只能收消息,不能执行普通命令(可用 SUBSCRIBE/UNSUBSCRIBE/PSUBSCRIBE/PING)。
步骤 2:发布消息
终端 B(判题服务):
127.0.0.1:6379> PUBLISH judge:result:1001 "{\"submissionId\":8801,\"verdict\":\"AC\",\"score\":100}"
(integer) 1
返回值 1 表示当前有 1 个订阅者收到了消息。终端 A 立刻显示:
1) "message"
2) "judge:result:1001"
3) "{\"submissionId\":8801,\"verdict\":\"AC\",\"score\":100}"
步骤 3:模式订阅一次监听一批频道
管理员控制台想监听所有用户的判题结果,用 PSUBSCRIBE 配合通配符:
127.0.0.1:6379> PSUBSCRIBE judge:result:*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "judge:result:*"
3) (integer) 1
判题服务再发一条:
127.0.0.1:6379> PUBLISH judge:result:1002 "{\"verdict\":\"WA\"}"
(integer) 1
管理端收到时会额外告诉你匹配的是哪个模式:
1) "pmessage"
2) "judge:result:*"
3) "judge:result:1002"
4) "{\"verdict\":\"WA\"}"
通配符支持 *(任意字符)、?(单字符)、[abc](字符集合)。比如 judge:result:100? 匹配 1000-1009。
步骤 4:退订与查看频道
127.0.0.1:6379> UNSUBSCRIBE judge:result:1001
127.0.0.1:6379> PUNSUBSCRIBE judge:result:*