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 的網頁通訊協定,允許伺服器單向地、即時地向客戶端(瀏覽器)推送數據。

它的運作方式非常簡單:

  1. 瀏覽器向伺服器的某個端點發起一個普通的 HTTP GET 請求。
  2. 伺服器「抓住」這個請求不放,保持連線開啟。
  3. 伺服器的 Content-Type 回應標頭設為 text/event-stream
  4. 每當有新事件發生時,伺服器就沿著這條開啟的連線,將格式化好的文字數據(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;

流程:

  1. 事件產生 (Publisher):貨車的 GPS 裝置上報位置給「位置服務」。該服務處理後,將訊息**發布(Publish)**到 location-updates 這個主題上。

  2. 後端處理 (Subscribers)

    • Pub/Sub 主題(如 Kafka 或 RabbitMQ)將事件分發給所有訂閱者。
    • 「數據庫存檔服務」收到事件,將其存入資料庫備份。
    • 「即時分發服務」也收到同一個事件,準備將其推送給前端。
    • 以上所有後端內部的通訊,都由 Pub/Sub 模式完成,服務之間互不干擾。
  3. 前端推送 (SSE 連線)

    • 當使用者打開追蹤頁面時,他的瀏覽器會與「即時分發服務」建立一條 SSE 連線。
    • 「即時分發服務」收到來自 Pub/Sub 的新位置後,立刻透過這條 SSE 連線,將新座標推送給對應的使用者瀏覽器。
    • 這最後一哩路,從後端到前端的即時數據傳遞,由 SSE 完美勝任。

在這個架構中,Pub/Sub 完美地解耦了後端複雜的業務邏輯,而 SSE 則作為最後一哩路,高效、可靠地將最終結果呈現在使用者面前。

結論

不要再問「Pub/Sub 和 SSE 哪個好?」,而應該問「在系統中,哪部分應該用 Pub/Sub,哪部分適合用 SSE?」。

  • 當需要在系統內部(後端)進行非同步、一對多或多對多的服務通訊時,請使用 Pub/Sub 模式。
  • 當需要將後端的事件結果,單向、即時地推送給網頁前端時,請使用 SSE 協定。

理解它們各自的定位和職責,就能設計出更清晰、更強大、更具擴展性的現代化應用程式。