)
Redis 發布訂閱Pub/Sub一、Pub/Sub 是什么想象一下訂單服務剛創建了一筆訂單庫存系統要減庫存、通知服務要發短信、分析平臺要記日志——如果每個服務之間都直接調 HTTP當第四個消費者加入時所有上游都得改代碼。這種網狀調用會隨著系統變大而崩潰。發布訂閱Pub/Sub翻轉了這種模型Publisher ──(msg)── Redis ──(fan-out)── Subscriber A ── Subscriber B ── Subscriber C核心思想發布者只管往頻道扔消息不關心誰在聽。訂閱者只管從頻道收消息不關心誰發的。Redis 作為中間人負責路由。二、Redis Pub/Sub 的三個核心命令命令作用PUBLISH channel message向頻道發送消息返回收到消息的訂閱者數量SUBSCRIBE channel [channel ...]訂閱一個或多個頻道精確匹配PSUBSCRIBE pattern訂閱匹配模式的所有頻道如order:*一個關鍵性質消息不落地。Redis 不存儲已發送的消息——如果訂閱者掉線了錯過就是錯過了。這是 Pub/Sub 和消息隊列RabbitMQ/Kafka的根本區別。三、Go 中的訂閱與發布訂閱者// 訂閱者開啟一個專用長連接持續接收消息pubsub:rdb.Subscribe(ctx,orders:new,payments:done)deferpubsub.Close()// Channel() 返回一個 Go channel把 Redis 的網絡流轉換為本地 channelch:pubsub.Channel()// 循環讀消息阻塞直到來消息或 ctx 取消formsg:rangech{fmt.Printf([%s] %s\n,msg.Channel,msg.Payload)}關鍵細節Subscribe()后 Redis 客戶端會分配一條專用 TCP 連接這條連接被鎖定在 Pub/Sub 模式不能再執行普通命令GET/SET 之類的。這也是為什么生產環境通常給 Pub/Sub 單獨配一個連接池。發布者// 發布一個 JSON 消息typeOrderEventstruct{OrderIDstringjson:order_idAmountfloat64json:amountStatusstringjson:status}event,_:json.Marshal(OrderEvent{OrderID:O-1024,Amount:99.9,Status:paid})n,_:rdb.Publish(ctx,orders:new,event).Result()fmt.Printf(消息觸達 %d 個訂閱者\n,n)PUBLISH的返回值是收到消息的訂閱者數量——如果返回 0說明沒人監聽消息丟了。這是 Pub/Sub 的fire-and-forget天性。模式訂閱用通配符監聽一批頻道// 訂閱所有 order 相關事件orders:created, orders:cancelled, orders:paid...pubsub:rdb.PSubscribe(ctx,orders:*)ch:pubsub.Channel()formsg:rangech{fmt.Printf([%s → %s] %s\n,msg.Pattern,msg.Channel,msg.Payload)}*匹配一個層級如order:*匹配order:new但不匹配order:item:stock。如果需要多級匹配可以用order:**取決于 Redis 版本。四、Pub/Sub 的消息可靠性問題Pub/Sub 設計上是一條廣播水管——水流過就沒了。什么時候會丟消息場景后果訂閱者未上線時發布消息消息丟失訂閱者的 Channel 緩沖區滿處理慢消息積壓Redis 客戶端可能主動斷連網絡閃斷期間的消息丟失Redis 宕機重啟所有訂閱關系 未發消息全部消失解決方案Pub/Sub Stream 雙通道Pub/Sub 負責實時推送Stream 負責消息持久化Publisher ──PUBLISH── Redis Pub/Sub ──實時推送── Subscriber ──XADD──── Redis Stream ──補償讀取── Subscriber掉線重連后在線時吃 Pub/Sub 的實時推送低延遲掉線后從 Stream 里按消費者組的 LastDeliveredID 往回拉取遺漏的消息這不是 Redis 內建功能而是應用層組合拳。五、Pub/Sub vs 其他消息模式維度Pub/SubRedis StreamsRabbitMQKafka消息持久化? 不持久化???消費確認? 無? XACK? ACK? offset commit回溯重復消費????延遲 1ms 1ms~ ms 級~ ms 級運維復雜度極低低中高適用場景實時廣播、緩存失效通知、WebSocket 跨節點同步事件日志、消息隊列、消費者組企業消息中間件大數據流處理一句話選型要實時 丟幾條沒事 → Pub/Sub要可靠 不能丟 → Streams。六、常見應用場景1. 跨節點緩存失效多個 Web 節點各自有本地緩存數據更新后通過 Pub/Sub 廣播一個cache:invalidate:user:42所有節點同時清掉本地緩存。這是 Redis Pub/Sub 最經典的生產場景。2. WebSocket 跨節點消息推送用戶連在節點 A 的 WebSocket 上但觸發消息的服務跑在節點 B 上。B 發 Pub/Sub 到 RedisA 訂閱并推給 WebSocket 客戶端。Socket.IO 的 Redis Adapter 就是這個原理。3. 配置熱更新配置中心更新配置后PUBLISH 一條通知。所有服務訂閱了config:reload收到后立刻拉取最新配置。七、本章要點要點一句話Pub/Sub 是廣播不是隊列消息發完就消失沒有重放、沒有回執一條長連接一個 PubSubSubscribe 后連接被專用不要混用PSubscribe 用*通配可以監聽整批頻道省去逐個 SUBSCRIBE可靠性靠組合拳Pub/Sub 做實時通道Stream 做補償兜底延遲極低亞毫秒級適合實時場景核心認知把 Pub/Sub 當成一個廣播喇叭而非消息倉庫來用就對了。