Cloud Pub/Sub (簡稱 Pub/Sub) 是一個全代管的即時訊息服務,主要用於應用程式之間的非同步通訊。它採用發布-訂閱(Publisher-Subscriber)的架構模式,讓資料產生者和使用者能夠獨立運作,大幅提升系統的彈性和可擴充性。
為什麼我們需要 Cloud Pub/Sub?
在現代的分散式系統中,不同的服務組件往往會面臨以下挑戰:
後端處理速度跟不上
當前端產生資料的速度遠大於後端處理的速度時,系統就會出現瓶頸。例如,電商網站在促銷活動期間,訂單產生的速度可能遠超過庫存系統的處理能力。
又或是遊戲架構,通常會有高低峰期,像白天線上可能只有 100 多人,但是晚上可能高達 10,000 人在玩遊戲,可是你後端只有一台機器,會來不及處理持續不斷送進來的資料,影響到使用者體驗。
流量衝擊與系統穩定性
資料處理來不及是一回事,請求突然暴增,直接衝擊到後端系統,很容易造成服務過載甚至當機,最好要有一個緩衝機制,先讓資料在某個地方「排隊」,不要直接「打進」後端,確保系統穩定。
系統耦合度過高
當系統元件之間過度依賴時,任何一點故障都可能影響整個系統的運作。Pub/Sub 扮演了一個「智慧排隊系統」的角色,讓訊息能夠讓各個服務單獨處理,不會因為某個服務壞掉,大家都不能再處理訊息。

MQTT 協定的演進與 Pub/Sub 的關係
在了 Pub/Sub 之前,早期有個協定叫做 MQTT(Message Queuing Telemetry Transport)。MQTT 最初由 IBM 在 1999 年開發,目的是為了在衛星網路中傳輸石油管線的感測器資料。目前也廣泛應用在物聯網的應用,例如收集各種感測器回傳的資料,或是從工產的生產線收集設備或產品資料,確保生產線沒有異常。
MQTT 採用發布-訂閱模式,在架構中,有三個核心角色:
發布者(Publisher):負責發送訊息到特定主題
訂閱者(Subscriber):或叫客戶端 (Client) 訂閱感興趣的主題並接收訊息
訊息代理(Message Broker):居中協調,負責接收、儲存和轉發訊息

這種模式的優點是發布者和訂閱者之間完全解耦,彼此不需要知道對方的存在,也不需要同時在線上。這種設計理念深深影響了後來許多訊息系統的架構,當然也包括 Pub/Sub。
Cloud Pub/Sub 的核心概念
Google Cloud Pub/Sub 沿用了 MQTT 的發布-訂閱概念,但針對雲端環境進行了大幅優化:
主題(Topic):
就像是一個訊息的分類標籤,發布者將訊息發送到特定主題中。例如,電商網站可能會有「user-clicks」、「purchase-events」等不同主題。
訂閱(Subscription):
代表對某個主題的訂閱關係。一個主題可以有多個訂閱,每個訂閱都會收到該主題的所有訊息副本,這讓同一份資料可以被多個不同的服務同時處理。
訊息(Message):
實際傳遞的資料內容,可以是 JSON、二進位資料或任何格式,每個訊息都有唯一的 ID 和時間戳記。
如下架構圖,Pub/Sub 的訊息傳送還可以分成 Pull 和 Push 兩種,Pull 是 Subscriber (或叫 Consumer) 主動去 Subscription 拉取訊息,如果要確保 Subscriber 能夠確實處理到每一筆訊息,適合使用 Pull 方式。如果希望訊息即時傳送出去,則建議使用 Push 方式。

Cloud Pub/Sub 的技術優勢
相較於傳統的訊息佇列系統,Pub/Sub 提供了幾個重要特性:
擴展性高
能夠處理每秒數百萬筆訊息,並且自動根據負載進行擴充,這種分散式的處理架構,遠遠超過傳統只能用一台機器處理的能力。
至少一次傳遞保證 (Exactly-Once Delivery)
確保每個訊息至少會被傳送一次,避免資料遺失。同時提供訊息確認機制,只有當訂閱者確認處理完成後,訊息才會從佇列中移除。
順序保證
透過訊息排序功能,可以確保相關訊息按照正確順序處理,這對金融交易相關應用特別重要。
無效信件處理 (死信佇列 Dead Letter Queue)
發送失敗的訊息暫存區 (Subscription),訊息在此不會再持續發送,由後端主動來收訊息 (Pull 模式)。

Pub/Sub 基本操作示範
建立 Pub/Sub Topic
接下來我們可以快速體驗一下 Pub/Sub 如何運作,我們先建立一個主題為叫 my-topic。
順便勾選「新增預設訂閱項目」:

從 Cloud Shell 發送串流訊息
然後打開 Cloud Shell,執行以下指令碼,它會每 10 秒鐘發出一個 Hello 訊息,加上發出訊息當下的時間:
while true; do gcloud pubsub topics publish my-topic --message="Hello! 時間:$(date '+%Y年%m月%d日 %H時%M分%S秒')"; sleep 10; done

接收 Pub/Sub 訊息
我們去訂閱項目 my-topic-sub 的「訊息」,按下「提取」:

接下來等幾秒鐘,就會馬上看到收到的訊息,非常快。
確認 Pub/Sub 訊息
而這些訊息是還沒有被確認的狀態,而且在「確認」欄位顯示為「已超過確認期限」,因為預設的確認截止時間是 10 秒 (可以延長),我的手速太慢,擷圖的時候已經超過時間了。
那我們就勾選「啟用確認訊息」,再按一次「提取」,它就會把最舊的兩筆訊息顯示一個「確認」按鈕,因為 Pub/Sub 重新傳送未確認的訊息,所以確認截止時間會重新計算,現在又可以按「確認」了。
這就是所謂的「At-least-once delivery」:確保訊息至少被傳遞一次。而且會持續重試,直到被確認為止,不然就是到了 7 天之後,訊息過期。
我們再按下「確認」的話,訊息才會被刪除,它們就不會再出現在訂閱項目中了。
你會發現這些訊息一直改變它的狀態,本來可以按確認的訊息,又會一個一個到期,你就直接再「提取」,它們又會不斷出確認按鈕,有點像在打遊戲的感覺!

停止發送訊息
最後記得在 Cloud Shell 那邊,按下 ctrl + C 喔,不然訊息會一直累積下去,你就確認不完喔!
前面提到的 Pub/Sub,只是讓傳過來的資料先暫時排隊起來,我們再用後端服務來消化資料。
但是如果資料多到「怎麼樣都處理不完」的話,就不得不介紹 Cloud Dataflow 這個服務,有需要可以參考《Dataflow 是什麼?跟 Apache Beam 有什麼關係?》這篇文章喔!