Pub/Sub vs SSE:別再搞混了!一個是後端架構,一個是前端協定
在現代應用開發中,「即時」和「事件驅動」已經成為標配。當討論這些技術時,Pub/Sub 和 SSE (Server-Sent Events) 這兩個名詞經常被提及,也因此常常被混淆。許多開發者會問:「應該用 Pub/Sub 還是 SSE 來實現即時功能?」
這個問題的答案是:可能兩個都需要。
因為它們根本不是競爭關係,而是在軟體架構中扮演不同角色的合作夥伴。本文將徹底釐清這兩者的差異,並展示它們如何協同工作,打造出強大、可擴展的即時系統。
Pub/Sub - 系統後台的「中央郵政系統」
想像一下訂閱 YouTube 頻道。作為一個訂閱者,只關心訂閱的頻道有沒有發布新影片。不需要認識影片創作者,更不用關心他什麼時候上傳。反過來,創作者也只需要將影片發布到他的頻道,完全不用理會是誰訂閱了他。
這就是 發布/訂閱 (Publish/Subscribe, or Pub/Sub) 模式的精髓。
Pub/Sub 是一種非同步訊息傳遞的設計模式,主要用於實現後端服務之間的解耦。
它由三個核心角色組成:
- 發布者 (Publisher):事件的產生者(例如:訂單服務、用戶註冊服務)。它只負責將訊息發布到一個特定的「主題」。
- 主題 (Topic):一個訊息分類的頻道或中介(例如:一個名為
order-created
的主題)。 - 訂閱者 (Subscriber):事件的消費者(例如:庫存服務、通知服務)。它對特定主題感興趣,並接收來自該主題的所有訊息。
為什麼要用 Pub/Sub?
核心目的只有一個:解耦 (Decoupling)!
- 位置解耦:發布者和訂閱者不需要知道對方的網路位置。
- 時間解耦:發布者和訂閱者不需要同時在線。發布者發送訊息後,訂閱者可以在稍後有空時再去處理。
- 同步解耦:兩者之間的通訊是非同步的,發布者發送訊息後可以立即去做其他事,不必等待訂閱者回應。
這在哪裡使用?
幾乎完全在後端服務之間。需要一個稱為訊息中介 (Message Broker) 的工具來實現它。
- 常見工具:Apache Kafka, RabbitMQ, Google Cloud Pub/Sub, Redis Pub/Sub。
** Pub/Sub 是一個強大的後端架構模式,用於打造可擴展、有彈性的分散式系統。**
SSE - 對瀏覽器的「即時廣播電台」
現在,想像在網頁上追蹤一場體育比賽的比分。不需要手動刷新頁面,比分、安打、出局數都會自動更新。
這就是 伺服器發送事件 (Server-Sent Events, or SSE) 的典型場景。
SSE 是一種基於標準 HTTP 的網頁通訊協定,允許伺服器單向地、即時地向客戶端(瀏覽器)推送數據。
它的運作方式非常簡單:
- 瀏覽器向伺服器的某個端點發起一個普通的 HTTP GET 請求。
- 伺服器「抓住」這個請求不放,保持連線開啟。
- 伺服器的
Content-Type
回應標頭設為text/event-stream
。 - 每當有新事件發生時,伺服器就沿著這條開啟的連線,將格式化好的文字數據(
data: ...\n\n
)推送給瀏覽器。
為什麼要用 SSE?
- 簡單:前端只需使用內建的
EventSource
API,後端也只需遵循簡單的文本格式。 - 標準與相容:它就是 HTTP,可以無縫通過各種防火牆和代理。
- 自動重連:這是 SSE 的一大殺手級特性。如果連線意外中斷(例如網路切換),瀏覽器的
EventSource
會自動嘗試重新連線。
這在哪裡使用?
在伺服器 (Server) 和前端瀏覽器 (Client) 之間。
- 典型場景:即時新聞、股票行情更新、訂單狀態追蹤、進度條顯示。
SSE 是一種輕量、可靠、專為「伺服器到客戶端」單向數據推送而生的網頁技術。
Pub/Sub vs SSE
用一張表格來清晰地對比它們:
特性 / 方面 | Pub/Sub (發布/訂閱) | SSE (伺服器發送事件) |
---|---|---|
類型 | 後端架構模式 | 前端通訊協定 |
參與者 | 後端服務 ↔ 訊息中介 ↔ 後端服務 | 後端伺服器 → 前端瀏覽器 |
通訊方向 | 由中介管理的多對多 (Many-to-Many) | 嚴格的單向 (One-Way) |
核心目的 | 服務解耦,系統彈性 | 向網頁推送即時更新 |
比喻 | 訂閱雜誌/YouTube 頻道 | 廣播電台 / P.A. 系統 |
實戰場景:即時物流追蹤系統
讓我們看看它們如何協同工作。為了讓這個流程更加視覺化,讓我們用一張圖來表示一個即時物流追蹤系統的數據流:
graph TD;
subgraph "後端架構 (Pub/Sub 模式)"
A["貨車 GPS 裝置"] --> B["位置服務 (Publisher)"];
B -- "發布事件" --> C{"Pub/Sub 主題<br>location-updates"};
C -- "分發給訂閱者" --> D["數據庫存檔服務 (Subscriber)"];
C -- "分發給訂閱者" --> E["即時分發服務 (Subscriber)"];
D --> F[("歷史軌跡數據庫")];
end
subgraph "前端通訊"
G["使用者瀏覽器"];
end
E -- "即時推送<br>(SSE 連線)" --> G;
%% Styling
style C fill:#FFE3E3,stroke:#B40000,stroke-width:2px;
style E fill:#D6E8FF,stroke:#0042A3,stroke-width:2px;
流程:
-
事件產生 (Publisher):貨車的 GPS 裝置上報位置給「位置服務」。該服務處理後,將訊息**發布(Publish)**到
location-updates
這個主題上。 -
後端處理 (Subscribers):
Pub/Sub 主題
(如 Kafka 或 RabbitMQ)將事件分發給所有訂閱者。- 「數據庫存檔服務」收到事件,將其存入資料庫備份。
- 「即時分發服務」也收到同一個事件,準備將其推送給前端。
- 以上所有後端內部的通訊,都由 Pub/Sub 模式完成,服務之間互不干擾。
-
前端推送 (SSE 連線):
- 當使用者打開追蹤頁面時,他的瀏覽器會與「即時分發服務」建立一條 SSE 連線。
- 「即時分發服務」收到來自 Pub/Sub 的新位置後,立刻透過這條 SSE 連線,將新座標推送給對應的使用者瀏覽器。
- 這最後一哩路,從後端到前端的即時數據傳遞,由 SSE 完美勝任。
在這個架構中,Pub/Sub 完美地解耦了後端複雜的業務邏輯,而 SSE 則作為最後一哩路,高效、可靠地將最終結果呈現在使用者面前。
結論
不要再問「Pub/Sub 和 SSE 哪個好?」,而應該問「在系統中,哪部分應該用 Pub/Sub,哪部分適合用 SSE?」。
- 當需要在系統內部(後端)進行非同步、一對多或多對多的服務通訊時,請使用 Pub/Sub 模式。
- 當需要將後端的事件結果,單向、即時地推送給網頁前端時,請使用 SSE 協定。
理解它們各自的定位和職責,就能設計出更清晰、更強大、更具擴展性的現代化應用程式。