Pub/Sub 是一種用於在應用程式和服務之間交換事件資料的訊息傳遞服務。透過解耦合 (decoupling) 傳送方和接收方,它允許獨立開發的應用程式之間進行安全且高可用的通訊。Pub/Sub 提供低延遲、持久的訊息傳遞,開發人員通常用它來實現非同步工作流程、分發事件通知,以及從各種流程或設備串流傳輸數據。
如前所述,Pub/Sub 是一個非同步的全域訊息服務。在 Pub/Sub 中有三個經常出現的術語:主題 (topics)、發布 (publishing) 和 訂閱 (subscribing)。
總結來說,一個生產者 (producer) 將訊息發布到一個主題,而一個消費者 (consumer) 則對該主題建立一個訂閱項目以接收訊息。
Pub/Sub 的核心價值 — 解耦合
以傳統的郵局系統為範例:
- 主題 (Topic) 📮:就像一個公開的郵政信箱地址(例如「市民意見箱」)。任何人都可以往這個地址寄信。
- 發布者 (Publisher) 📤:寄信的人。他們只在乎把信(訊息)投到正確的信箱地址(主題),並不在乎是誰、何時、或有多少人會來收信。
- 訂閱者 (Subscriber) 📥:擁有這個信箱鑰匙並來取信的人。他們只關心信箱裡有沒有信,並不在乎是誰寄的。
這種「寄信的不管收信的,收信的不管寄信的」模式就稱為解耦合。它的好處是:
- 彈性:可以隨時增加新的收信人(訂閱者),而寄信的系統完全不需要修改。
- 可靠性:即使收信的系統暫時故障,信件(訊息)也會安全地存放在郵局(Pub/Sub),等系統恢復後再來取即可,訊息不會遺失。
- 非同步處理:寄信人投遞後就可以離開了,不用在原地等到收信人來取信。這讓系統可以更有效率地處理工作,不會被卡住。
Pub/Sub 已經預先安裝在 Cloud Shell 中,所以不需要進行任何安裝或配置。
建立一個名為 myTopic
的主題:
gcloud pubsub topics create myTopic
為了練習,再建立兩個主題:一個叫做 Test1
,另一個叫做 Test2
:
gcloud pubsub topics create Test1
gcloud pubsub topics create Test2
列出所有 topics
gcloud pubsub topics list
清理:刪除 Test1
、Test2
gcloud pubsub topics delete Test1
gcloud pubsub topics delete Test2
確認主題已被刪除,再次執行 gcloud pubsub topics list
指令:
gcloud pubsub topics list
應該只會看到剩下的 myTopic
在 myTopic
主題上建立訂閱 mySubscription
gcloud pubsub subscriptions create --topic myTopic mySubscription
再建立兩個訂閱 Test1
、Test2
gcloud pubsub subscriptions create --topic myTopic Test1
gcloud pubsub subscriptions create --topic myTopic Test2
列出 myTopic
的所有訂閱
gcloud pubsub topics list-subscriptions myTopic
一對多廣播 (Fan-out)
注意,我們為 一個 主題 (
myTopic
) 建立了 三個 訂閱項目。
→ 這是一個重要的模式,稱為「扇出 (Fan-out)」。當一則訊息被發布到
myTopic
時,Pub/Sub 會將這則訊息的 副本 傳送給 所有 訂閱該主題的訂閱項目(mySubscription
,Test1
,Test2
)。每個訂閱項目都會獨立地接收和處理這條訊息。e.g. 一個「新訂單成立」的主題,可以同時被「庫存系統」、「出貨系統」和「數據分析系統」訂閱。一筆新訂單的訊息發出後,這三個系統會同時收到通知並各自進行處理,互不干擾。
概念小測驗:
要接收某 topic 的訊息,是否必須建立該 topic 的 subscription?
✅是(True)。沒有訂閱就沒有「收件匣」,訊息無處投遞。
刪除 Test1
和 Test2
訂閱項目 並確認:
gcloud pubsub subscriptions delete Test1
gcloud pubsub subscriptions delete Test2
gcloud pubsub topics list-subscriptions myTopic
接下來學習如何發布訊息到 Pub/Sub 主題。
"Hello"
發布到之前建立的 myTopic
主題:gcloud pubsub topics publish myTopic --message "Hello"
myTopic
(將 <YOUR NAME>
換成自己的名字,<FOOD>
換成自己喜歡的食物):gcloud pubsub topics publish myTopic --message "Publisher's name is <YOUR NAME>"
gcloud pubsub topics publish myTopic --message "Publisher likes to eat <FOOD>"
gcloud pubsub topics publish myTopic --message "Publisher thinks Pub/Sub is awesome"
接下來,使用 pull
指令來從主題取得訊息。pull
指令是基於訂閱項目的,這意味著它能運作是因為先前為 myTopic
主題設定了 mySubscription
這個訂閱項目。
提取剛剛發布的訊息:
gcloud pubsub subscriptions pull mySubscription --auto-ack
輸出應該會類似這樣,只顯示一則訊息:
pull
預設只取一則。pull
出來且 ack 的訊息,同一個 subscription 之後就拿不到(已確認)。pull
,直到訊息被拿光;再跑就會看到 Listed 0 items.
。現在,執行第四次。會得到以下輸出(因為已經沒有訊息可以回傳了):
Listed 0 items.
訊息的生命週期與確認 (ACK)
這個「拉一次就不見」的行為是 Pub/Sub 可靠性的核心機制,關鍵在於
--auto-ack
這個旗標。
- ACK 是 Acknowledge (確認) 的縮寫。
一則訊息的旅程是這樣的:
- 發布 (Publish):訊息進入主題,並被複製到
mySubscription
訂閱項目的佇列中。- 提取 (Pull):
pull
指令從mySubscription
請求訊息。Pub/Sub 將一則訊息傳送給我們,並暫時將其標記為「處理中 (in-flight)」。此時這則訊息對其他pull
請求是不可見的。- 自動確認 (Auto-Ack):
-auto-ack
旗標告訴gcloud
工具:「一旦成功顯示了這則訊息,就立刻自動回報給 Pub/Sub 說『我處理完了,可以把它刪掉了』」。- 刪除:Pub/Sub 收到確認後,就會從訂閱項目的佇列中永久刪除這則訊息。
這就是為什麼無法再次提取到同一則訊息的原因。這個機制確保了每條訊息都只會被成功處理一次。如果程式在處理訊息時崩潰而沒有發送 ACK,Pub/Sub 在等待超時後會讓這則訊息重新變為可提取狀態,以供其他消費者處理。
由於在 Task 3 中已經提取了所有訊息,現在讓我們為 myTopic 再填充一些新訊息。
gcloud pubsub topics publish myTopic --message "Publisher is starting to get the hang of Pub/Sub"
gcloud pubsub topics publish myTopic --message "Publisher wonders if all messages will be pulled"
gcloud pubsub topics publish myTopic --message "Publisher will have to test to find out"
limit
旗標的 pull
指令:現在,在指令中加入一個旗標 (flag),這樣就可以在一次請求中輸出所有三則訊息。
gcloud pubsub subscriptions pull mySubscription --limit=3
輸出會一次顯示三則訊息:
建立 topic:gcloud pubsub topics create <TOPIC>
列出 topics:gcloud pubsub topics list
刪除 topic:gcloud pubsub topics delete <TOPIC>
建立 subscription(綁定 topic):
gcloud pubsub subscriptions create --topic <TOPIC> <SUBSCRIPTION>
列出某 topic 的 subscriptions:
gcloud pubsub topics list-subscriptions <TOPIC>
刪除 subscription:gcloud pubsub subscriptions delete <SUBSCRIPTION>
發佈訊息:
gcloud pubsub topics publish <TOPIC> --message "..."
(也可用 --attributes key=value,...
傳自訂屬性)
拉取訊息(預設 1 則):
gcloud pubsub subscriptions pull <SUBSCRIPTION> --auto-ack
常用旗標:
-limit=N
:上限 N 則-auto-ack
:抓到就自動 ackmodify-ack-deadline
或 SDK 手動 ack