💡 先搞懂問題
虛構的「晴空食品」有一套線上訂購系統。顧客送出訂單後,系統要通知倉庫備貨、請帳務系統開發票、替會員加點數,還要把訂單寫進資料倉儲做報表。第一版的寫法是下單 API 依序呼叫這四個服務,全部成功才回應顧客。上線之後,倉庫系統每天凌晨更新要停機十分鐘,這段時間的訂單全部失敗;母親節檔期一開跑,請求一路壓到帳務系統,整個網站跟著變慢;行銷部門想再接一個推薦系統,工程師只好又改一次下單程式、重新測試部署。
這是典型的緊耦合(tight coupling):上游要等下游回應,下游一慢、一掛,上游就跟著失敗;每多一個下游,上游就多一段程式。解法是解耦(decoupling):下單服務只負責宣布「有一筆新訂單」,至於誰要處理、什麼時候處理、失敗要不要重試,交給中間那一層和各個下游自己決定。在 Google Cloud 上,這一層最常用的就是 Pub/Sub:發布者(publisher)把訊息送到主題(topic),每個訂閱(subscription)各自收到一份,訂閱背後的程式(訂閱者,subscriber)處理完要回覆確認(acknowledge,簡稱 ack)。
生活比喻:報社發報與訂戶簽收
想像一家報社。編輯部每天出一份報紙,不需要知道是誰在看,只要把報紙交給發行部。發行部手上有一份訂戶名冊,名冊上每一戶都會收到一份完整的報紙,多一戶就多印一份,少一戶也不影響其他人。有些訂戶是一整間公司,公司收發室收到報紙後,交給當天有空的同事分頭剪報,同一份報紙只要一位同事處理就好。
報紙送到之後,訂戶要在送報員規定的時間內簽收。沒簽收,送報員就當作沒送到,晚點再送一次;有些訂戶故意不簽,是因為報紙被雨淋濕了,請送報員再送一份。如果同一份報紙送了五次都沒人簽收,發行部不會無止境地送下去,而是把它轉到客服部的「異常件」櫃,等客服人員來查原因。
這個比喻有三個地方和實際不同,剛好也是考試常考的地方。第一,報社一份報紙只送一次,但 Pub/Sub 預設是至少傳遞一次(at-least-once),偶爾同一則訊息會送到兩次,而且不保證順序,所以處理程式要寫成重複執行也不會出錯,也就是等冪(idempotent);真的要避免重送,可以在提取訂閱開啟恰好一次傳遞(exactly-once delivery),要依序就用排序鍵(ordering key)。第二,送報員會依自己的路線決定什麼時候補送,Pub/Sub 則讓你在訂閱上設定重試政策(retry policy):預設是立即重送,也可以改成指數退避(exponential backoff),每次失敗後等久一點再送。第三,客服的異常件櫃一定有人看,但無效信件主題只是另一個主題,它底下沒有訂閱的話,轉過去的訊息就會遺失,而且 Pub/Sub 要有權限才能把訊息轉過去,這兩點在操作教學會實際設定。
新手最常卡在哪裡
第一個坑是確認期限比處理時間短:確認期限預設只有 10 秒,處理一筆要 30 秒的程式還沒做完,訊息就被重送給別人,同一張訂單出貨兩次;用 Google 提供的用戶端程式庫時,程式庫會自動延長期限(租約管理),但直接呼叫 API 或用推送訂閱時,就要自己把期限設對。第二個坑是沒有設無效信件主題:一則格式錯誤的訊息每次處理都失敗,就一直被重送,佔用訂閱者,開了排序時還會卡住同一個排序鍵後面的所有訊息。第三個坑是設了無效信件主題卻沒給權限、或沒替它建訂閱:Pub/Sub 轉不過去,或轉過去卻沒人收。第四個坑是選錯服務:把 Pub/Sub 當成可以指定時間、控制速率的工作佇列,或拿它做多步驟流程。實驗室一處理前三個坑,實驗室二處理第四個。
🎮 互動實驗室一:Pub/Sub 傳遞模擬器
晴空食品的主題 orders 上有一個倉庫用的訂閱 orders-warehouse,裡面有 5 筆訂單,由三個訂閱者(或推送端點的三個處理槽)同時處理。其中訂單 #102 的地址格式錯誤,是一則毒訊息(poison message):每次處理到第 3 秒就失敗並回覆否定確認。左邊調整訂閱類型、確認期限、正常訂單的處理時間、最大傳遞次數、重試政策,以及要不要設無效信件主題、自動延長期限、恰好一次傳遞與訊息排序;右邊按「下一個事件」一步一步看訊息被交付、確認、逾時重送,或被轉到無效信件主題,也可以按「自動播放」或「跳到結束」。設定一改,模擬就從頭開始。跑完會檢查下方三個挑戰目標,並說明原因。
一、訂閱設定
二、挑戰目標
訂閱 orders-warehouse 的待處理訊息 提取訂閱
無效信件主題 orders-dlq → orders-dlq-sub
行為依 Pub/Sub 官方文件「Dead-letter topics」「Subscription retry policy」「Exactly-once delivery」「Order messages」「Push subscriptions」與 gcloud 指令參考(查證時間 2026 年 10 月)。為了看得懂,模擬做了幾個簡化:時間以秒為單位、每個訂閱者一次只處理一則、閒置的訂閱者會立刻拿到下一則;指數退避的等待時間用「10 秒起、每次加倍、最長 600 秒」示意,官方只保證介於你設定的最小與最大值之間逐次拉長;官方說明最大傳遞次數是「大約」,實際可能多幾次或少幾次才轉送,模擬一律剛好在達到上限時轉送。沒開恰好一次傳遞時,「至少一次」的偶發重送在真實環境無法預測,模擬固定讓 #202 在確認後 2 秒被重送一次來呈現;期限過後才送達的確認,若訊息還沒被重新交付,模擬當作確認成功(盡力而為),若已重新交付就當作無效。推送訂閱的整體退避(100 毫秒~60 秒)與推送視窗沒有模擬。
🎮 互動實驗室二:情境分診,這該用哪個服務?
下面有 10 張虛構公司的情境卡。讀完情境與卡片下方的關鍵需求,從 8 個選項裡點一個最適合的服務或 Pub/Sub 訂閱類型,畫面會立即說明對錯與原因;答錯也可以再點其他選項,看看差在哪裡。上方的圓點可以跳到任一張卡,全部答完會顯示總結。注意 Pub/Sub Lite 已在 2026-03-18 關閉,所以不在選項裡。
🛠️ 操作教學:建立主題、訂閱與無效信件主題
不用登入 Google Cloud,也能先把流程走一遍:選專案並啟用 Pub/Sub API、建立主題 orders、建立無效信件主題與它的訂閱、建立倉庫用的訂閱並設定確認期限、無效信件與重試政策、授予 Pub/Sub 服務代理權限、發布一則測試訊息,最後提取並確認。左邊是簡化的主控台,右邊同步顯示等效的 gcloud 指令與 Terraform,黃色底的那幾行就是目前這一步對應的內容。可以故意填錯名稱或數字看看驗證訊息,也可以改名稱、傳遞類型或重試政策,看右邊怎麼跟著變。
terraform destroy,它建立的主題、訂閱與 IAM 繫結會一起刪除。想讓 Google 代管 Terraform 的執行與狀態檔,可以用 Infrastructure Manager;舊的 Deployment Manager 已經停止支援、2027-06-30 之後關閉,新專案不要再用。
自己動手時要注意
權限方面,建立與刪除主題、訂閱,發布與提取訊息,用 Pub/Sub 編輯者(roles/pubsub.editor)就夠;但它沒有設定 IAM 政策的權限,第 6 步替服務代理授予角色要用 Pub/Sub 管理員(roles/pubsub.admin)或專案擁有者。如果還沒啟用 Pub/Sub API,啟用時需要專案層級的服務使用權限(例如 Service Usage 管理員)。無效信件要能運作,Pub/Sub 服務代理 service-專案編號@gcp-sa-pubsub.iam.gserviceaccount.com 必須在無效信件主題上有 roles/pubsub.publisher(才能把訊息轉過去),在原本的訂閱上有 roles/pubsub.subscriber(才能把轉走的訊息從原訂閱確認掉);官方文件也提醒,權限沒設好時傳遞次數不會被計算。注意這裡要的是「專案編號」不是專案 ID,可以用 gcloud projects describe 查。推送訂閱若開啟驗證,建立訂閱的人還要能「以該服務帳戶身分執行」(iam.serviceAccounts.actAs);寫入 BigQuery 的訂閱,資料表要先建好,服務代理也要有寫入那張資料表的權限。
費用方面,Pub/Sub 依傳輸的資料量計費,練習量通常很小;但沒設無效信件主題的毒訊息會一直重送,訊息保留與主題保留也會產生儲存費用。新帳戶的免費試用是 90 天、300 美元抵用金,另有每月的免費用量(查證日期 2026-10-08,實際條件以 Google Cloud 免費方案頁為準)。範例裡的專案一律用 my-project-id、PROJECT_NUMBER 這種佔位,不要把服務帳戶金鑰下載到電腦或寫進腳本;在 Cloud Shell 或用自己的使用者憑證(gcloud auth login)操作即可,CI/CD 等外部系統請改用 Workload Identity Federation。訊息內容不要放個資或密碼。練習完依下面的順序刪除(刪除主題不會自動刪除它的訂閱,訂閱要另外刪):
📘 原理補完
主題、訂閱、訂閱者:三層關係先分清楚
Pub/Sub 的資源只有兩種要建立:主題與訂閱,兩者都是專案層級的全域資源,不必選 Region,也不用預先規劃分割區或分片,容量會自動擴展。訊息發布到主題時,Pub/Sub 會替主題上每一個訂閱各保留一份;訂閱建立之前發布的訊息,新訂閱預設收不到(除非主題開了訊息保留,再用 seek 回到過去的時間點)。同一個訂閱底下可以有很多個訂閱者程式,它們分攤這個訂閱的訊息,每則只交給其中一個。所以題目說「三個系統都要收到每一筆訂單」,答案是三個訂閱;說「同一個系統要加開處理程式分攤負載」,答案是同一個訂閱多開幾個訂閱者。
幾個常用的上限與預設值(依 Pub/Sub 官方文件與本站節點,查證時間 2026 年 10 月):訊息資料最大 10 MB、每則最多 100 個屬性;每個主題最多 10,000 個訂閱;訂閱預設保留未確認訊息 7 天,可設 10 分鐘到 31 天;主題也能設訊息保留(10 分鐘到 31 天),讓訂閱用 seek 重播;訂閱閒置 31 天預設會過期刪除。訂閱還可以設篩選條件(filter),只收符合屬性的訊息,但篩選條件建立後就不能修改。
| 項目 | 提取訂閱 | 推送訂閱 | 匯出訂閱(BigQuery/Cloud Storage) |
|---|---|---|---|
| 誰發起傳遞 | 訂閱者呼叫 Pull/StreamingPull | Pub/Sub 以 HTTPS POST 送到端點 | Pub/Sub 直接寫入目的地 |
| 怎麼算確認 | 程式呼叫 acknowledge | 端點回 102、200、201、202、204 | 寫入成功即確認 |
| 確認期限 | 可由程式延長(用戶端程式庫自動處理) | 同時是推送請求逾時,不能對單則延長 | 由服務處理 |
| 恰好一次傳遞 | 支援(訂閱者連同一 Region) | 不支援 | 不支援 |
| 排序 | 支援 | 支援,但每個排序鍵一次只有一則在途 | 依目的地而定(本頁不展開) |
| 適合 | 常駐、高吞吐、要自己控速 | 無伺服器、可縮到零的服務 | 原封不動落地分析或封存 |
一則訊息的一生:確認期限、重試政策與傳遞次數
訊息交給訂閱者那一刻開始,確認期限開始倒數(預設 10 秒,可設 10~600 秒)。期限內收到確認,這則訊息在這個訂閱就算處理完;收到否定確認,或期限到了都沒有回覆,Pub/Sub 會再傳一次。什麼時候再傳由重試政策決定:預設是立即重試,可能馬上又送回同一個訂閱者;改成指數退避後,每次失敗會等一段逐次拉長的時間,你可以設最小與最大退避(各 0~600 秒,預設 10 秒與 600 秒),而且退避是逐則訊息計算,不會拖慢其他訊息。官方也提醒,重試政策不是拿來刻意延遲訊息的工具,要排定未來時間執行請用 Cloud Tasks。
設定了無效信件主題之後,Pub/Sub 會計算每則訊息的傳遞次數:1 加上「否定確認次數」再加上「確認期限逾時次數」。次數達到最大傳遞次數(5~100,預設 5)還是沒被確認,就轉到無效信件主題。官方特別說明這個次數是「大約」的,屬於盡力而為,可能早幾次或晚幾次轉送;訊息裡會帶著目前的傳遞次數(提取訂閱是 delivery_attempt 欄位,推送是 deliveryAttempt),程式可以據此決定要不要記錄或特別處理。
無效信件主題與服務代理權限
無效信件主題本身就是一個普通主題,設定是放在訂閱上,不是放在原本的主題上。官方文件的幾個重點:它必須和訂閱所附加的主題不同;可以放在別的專案;Pub/Sub 只是把訊息「發布」過去,所以無效信件主題底下一定要先建好訂閱,不然發布到沒有訂閱的主題,訊息就遺失了。轉送這個動作是由 Pub/Sub 服務代理(每個專案一個,格式是 service-專案編號@gcp-sa-pubsub.iam.gserviceaccount.com)代你執行:它要能發布到無效信件主題(roles/pubsub.publisher),也要能在原訂閱上把轉走的訊息確認掉(roles/pubsub.subscriber)。少了任何一個,訊息就會停在原訂閱一直重試,傳遞次數也不會被計算。
恰好一次傳遞與訊息排序:條件與代價
恰好一次傳遞只支援提取訂閱(包含 StreamingPull),而且訂閱者要連到同一個 Region 才有保證。開啟後,Pub/Sub 保證兩件事:訊息成功確認之後不會再被送出;在確認期限內(訊息還在途中)也不會重送給別人。它不保證你的處理程式只執行一次:處理時間超過確認期限,訊息照樣會重新交付,這時舊的確認會失敗並回傳錯誤(官方建議用「確認並取得回應」的介面,才知道確認有沒有成功);發布端因為重試而送了兩次的訊息,會是兩個不同的訊息 ID,也不在保證範圍內。代價是發布到接收的延遲明顯變高。
訊息排序要兩邊配合:訂閱建立時開啟訊息排序(建立後不能改),發布者替相關的訊息設相同的排序鍵,而且同一個排序鍵要從同一個 Region 發布。沒有排序鍵的訊息不排序。每個排序鍵的發布吞吐量上限是 1 MBps;某一則訊息被重送時,同一個排序鍵後面的訊息(包含已確認的)也會跟著重送;推送訂閱每個排序鍵一次只有一則在途。無效信件主題是盡力而為,轉送過去的訊息順序可能不會保留。
遇到題目時的判斷步驟
- 是不是固定時間觸發(每天、每小時)?是就選 Cloud Scheduler,取代 VM 上的 crontab。
- 是不是 Google Cloud 的事件(值區裡的物件建立、稽核記錄裡的 API 呼叫、第三方事件)發生後要自動執行程式?是就選 Eventarc,事件以 CloudEvents 格式送到 Cloud Run 等目標。
- 是不是多步驟流程,要依序呼叫、分支、等待人工核准或回呼?是就選 Workflows。
- 是不是要由發送端指定目標、控制每秒幾次、排定未來時間?是就選 Cloud Tasks(明確呼叫)。
- 已經在用 Kafka API、Kafka Connect,要最少修改搬上雲?選 Managed Service for Apache Kafka(Pub/Sub Lite 已在 2026-03-18 關閉,不是選項)。
- 剩下的「一對多扇出、削峰緩衝、串流擷取」選 Pub/Sub,再依處理端挑訂閱類型:常駐程式自己拉選提取;Cloud Run 這類可縮到零的服務選推送;不轉換、直接落地到 BigQuery 或 Cloud Storage 選匯出訂閱。
容易考錯的地方
要讓三個系統都收到,就讓它們訂同一個訂閱:不對。同一個訂閱的訂閱者是分攤訊息,每則只給一個;要每個系統都收到,就要為每個系統各建一個訂閱。
訊息被重複處理,就調高最大傳遞次數或延長訊息保留:都無關。重複處理通常是處理時間超過確認期限(調大期限或讓程式庫延長租約),或本來就是至少一次的偶發重送(處理程式要等冪,必要時在提取訂閱開恰好一次傳遞)。最大傳遞次數決定何時放棄,保留期間決定訊息最多放多久。
恰好一次傳遞可以用在推送訂閱:不行,只有提取訂閱支援,而且訂閱者要連同一 Region。推送到 Cloud Run 的情境,答案通常是把處理程式寫成等冪。
設了無效信件主題就萬事 OK:還要授予服務代理兩個角色(無效信件主題的發布者、原訂閱的訂閱者),並替無效信件主題建一個訂閱,否則轉過去的訊息沒人保存。最大傳遞次數最低是 5,題目出現 1、2、3 都是不合法的值。
重試政策可以用來延後處理:官方不建議。指數退避是用來給失敗的訊息喘息時間;要「30 分鐘後再做」請用 Cloud Tasks 的排定時間。
要順序就整個系統用同一個排序鍵:這會讓所有訊息排成一列、吞吐量被每個鍵 1 MBps 卡住。排序鍵要用最小的保序單位;訊息排序也只能在建立訂閱時開啟。
要把 Pub/Sub 訊息存進 BigQuery,一定要寫 Dataflow:不用轉換時,BigQuery 匯出訂閱就能直接寫入;要轉換、彙總、視窗計算時才需要 Dataflow。
Pub/Sub Lite 比較便宜,所以選它:Pub/Sub Lite 已在 2026-03-18 關閉,官方替代是 Managed Service for Apache Kafka 或 Pub/Sub。舊教材或考試大綱若還出現,當成歷史名詞即可。
相關考試:依 Google Cloud 各考試官方 exam guide(查證時間 2026 年 10 月),Pub/Sub 在 CDL、ACE、ADP、PCD、PDE、PCDOE 的服務清單中被點名,PCA 則點名了 Pub/Sub 模擬器。ACE 與 PCD 偏重訂閱類型、確認與重試的設定細節,PDE 與 ADP 偏重串流擷取(Pub/Sub 到 Dataflow 或 BigQuery),PCD 也考 Pub/Sub、Cloud Tasks、Eventarc、Cloud Scheduler、Workflows 的分工。
✅ 自我檢測
6 題原創題,選完立即顯示對錯與解析,全部作答後會出現總分。目前得分:0 / 6