昨天我們完成了用 WebSocket 將站內信通知推送給客戶端的用戶,流程大致上是用戶打開我們的應用時,觸發了一個 WebSocket 連接請求到後端,後端 ws//: 收到請求後也回應了,於是這個協議升級的動作就完成,前後端就建立起了 WebSocket 的連接,這個連接的狀態會一直保存在後端服務器,只要這個狀態一直都 isOpen 就可持續通信,但問題就來了,萬一我們現在因為用戶流量增加,需要為我們的 Server 實例做水平擴展,假設跟用戶取得連接的是 Server A,但處理推送的是 Server B,這樣 Server B 沒有跟用戶連接的狀態啊,這樣怎麼搞?所以這時就有必要引入 Redis Pub/Sub 來保存分布式環境下 WebSocket 的狀態了。
Redis Pub/Sub 是一個訂閱發布的模式,它可以在發布者不知道訂閱的人是誰的情況下發送消息,訂閱者自己會訂閱 Channel 來接收,這種模式實現訂閱發布消息的解耦。這個模式有以下幾個特性:
那它在我們的系統裡要幹嘛?
Kafka 也是 Pub/Sub 模式但它主要負責擔任的是業務邏輯的載體,是真正出貨的工廠,Redis 比較像分流的角色,分到對應的 WebSocket 推送器。Kafka 的消息是持久化且有序的,還有重試的機制,這對業務邏輯來說很重要,所以 Kafka 負責裝真正的業務消息,Redis Pub/Sub 裝輕量的通知路由消息。但為何不能擇一就好?因為 Kafka 延遲時間比較長,又更適合做批量、高吞吐的工作,資源消耗大,送一些小東西大才小用,而 Redis Pub/Sub 如果裝業務邏輯的消息,它又沒持久化,消息丟了就沒了,也沒消息確認機制,無法保證消息被正確處理,不適合處理負責業務邏輯跟大量數據。
話說為何要用 Redis Pub/Sub 而不是直接把 WebSocket Session 放到 Redis 裡,要推送的實例自己去 Redis 取用呢?因為 WebSocket Session 是不可序列化的 JVM 實例,它有本地性,無法存到 Redis 給其他實例使用,所以它只會傳遞推送的命令,由保有該連接的實例收到命令後推送出去。
今天先把一些理論前導一下就好,明天再開始實作基礎的配置跟簡單測試: