集結國內外精選文章,掌握最新雲端技術新知與應用
最近有機會在 GCP 上開發分散式的系統,透過 GCP Cloud Pub/Sub 來解決我們系統上的瓶頸,於是整理了有關 Pub/Sub 的使用心得與經驗,同時與過去使用 Amazon Simple Queue Service (SQS) 比較。
在 Pub/Sub 中有下列角色:
• Pub/Sub topic: Publish application 可以創建 topic 用來發送 messages (tasks) 到此 topic。 • Pub/Sub subscription: Subscriber applications 可以建立多個 subscription 訂閱同一個 topic,當此 topic 有新的 messages 時,會同時發送到所訂閱的 subscription。 • Publisher application: 發送 messages 到特定的 Pub/Sub topic。 • Subscriber application: 從特定的 Pub/Sub subscription 接收 messages、處理。
與 AWS SQS 較大的不同是,在 Pub/Sub 中,可以支援出 one-to-many (fan-out), many-to-one (fan-in), many-to-many 的系統架構。
Pub/Sub 主要處理的流程如下:
1. Publisher application 在 Pub/Sub 中創建一個 topic,然後可以將 messages 傳送至這個 topic 中。 2. 被傳送至 topic 中的 message,在被處理 (收到 subscriber 的 acknowledge request) 前,會被保存在這個 topic 中 (預設為保留七天,七天之後如果 Pub/Sub 都沒有收到 acknowledge request 的話,Pub/Sub 會自動刪除這筆 message)。 3. Subscriber applications 向 Pub/Sub 訂閱 subscription 後,所有被發送到 topic 的 messages 都會發送到 定閱的 subscriptions,這時候 subscriber applications 可以有兩個動作: 4. 主動向 Pub/Sub 發送 pull 請求,拿到 messages。 5. 設定 public endpoint 讓 Pub/Sub 推送給你的 subscribers。 6. Subscriber applications 在處理完 message 後,會依照 message id (每個 message 都有的 unique id),發送 acknowledge request 給 Pub/Sub,以確定訊息已經處理完成。 7. 當 Pub/Sub 收到某一 message id 的 acknowledge request 後,會將此 message 從 Pub/Sub 中刪除。
天生就可以實作 many-to-many 架構,透過 Pub/Sub 作為中間橋接的角色,使用者只需要專注在不同 subscriber 的開發。
Pub/Sub 支援 push 和 pull 兩種 subscription (AWS SQS 中只支援 pull)
在 push subscription 是被動等待訊息推送過來,因此在 subscriber 必須實作一個 HTTP Server 等待 Pub/Sub 推送訊息。當 Pub/Sub 一收到訊息會立即推送到 endpoint,適合即時性高的服務。
Pull subscription 顧名思義就是 subscriber 定期向 Pub/Sub pull message 進行處理。而在 Google 所提供的 Node.js SDK 中,又有兩種 pull 的方法:
對開發者來說,只要去透過 Node.js 監聽 Pub/Sub 的 event 就好,當有新的 message 進到 subscription 時,會觸發 message event 的 callback。但是請記得處理完拉到的 message 後要針對這筆 message 發送 acknowledge request,不然 subscriber 會一直處理到相同的 message。
透過 subscriber 主動到 Pub/Sub 抓取 message 下來處理。此方法的優點是速度可以由 subscriber 控制,做完手上的任務後再抓取新的 message。不會對 subscriber 造成太大的效能問題。
我覺得 AWS SQS 最大的優勢有兩個:
支援 dead letter queue。可以在設定當一個 message 被 subscriber re-try 幾次之後,就自動 forward 到 dead letter queue 中。
這樣的好處在於,如果有一筆 message 是有問題的 (例如資料格式錯誤或是不在存時),在 subscriber re-try 幾次之後,AWS SQS 會自動將這筆 message forward 到你指定的 dead letter queue 中。而不會繼續留在原本的 queue 中佔用 subscriber 的資源。
在某些 region 已經有 first-in/first-out 的 queue 了,可以針對你系統的需求使用。
一開始在使用 Pub/Sub 時,每天都在懷疑人生 XD,因為不管再怎麼調整都達不成我們一開始設定的容量目標,心想到底是 Google 服務有問題,還是我們不會使用 XD
1. 為什麼 scale out 了 subscriber,Pub/Sub 的 query per second (qps) 還是這麼低? 會造成這個現象,可能會有幾個原因:
• 如果你是使用 pull 的話,是否 subscriber 處理每個 message 的時間太久了,特別是在處理任務時,需要用到網路、I/O 等資源。當處理 message 的時間變長了,就會影響到 subscriber pull message 的次數,進而造成 qps 低落。
• 是否你在同一個小資源的平台上(例如一台 VM 上)跑了多個 subscriber,進而讓 VM 上的資源限制住 subscriber 的處理速度。
2. Acknowledge deadline 的重要性
• 在設定 acknowledge deadline 時,請設定一個 「合理」、「安全」 的時間。因為只要當 acknowledge deadline 時間一到,你還沒有針對此筆 message 發送 acknowledge request 的話,這筆 message 就會重新回到 Pub/Sub 中,讓下一個 subscriber 拿取,會造成 message 被重覆(duplicate) 做了多次。 • 一般會估算處理 message 的最大處理時間,例如為 1 分鐘,而保險的做法就是將 acknowledge deadline 設為比處理時間長的時間,例如: 2–3 分鐘。 • Pub/Sub 同時也提供 modify ack deadline 的 API,可以在 deadline 快到時延長時間。
3. 目前在 Pub/Sub 中不保證訊息的順序性
4. Message 可能會發生重覆(duplicate),有兩種處理方式
• Message 不能重覆執行,就需要在 message 夾帶的 unique id 在執行的時候進行確認,如果已經執行過,就 by pass,並且發送 acknowledge request 將它從 Pub/Sub 中移除。確認的方式可以透過像是將 uuid 存在 Redis 這種 thread safe 的 DB 中,以確保不同的 subscriber 不會互相做到相同的 message。 • Message 可以重覆執行,程式便能忽略重覆性確認的流程。但是需要注意的是 「重複執行了幾次」 需要 subscriber 計算,如果真的重做了很多次 (例如 100 次) 則需要對此 message 做特別的處理,例如將此 message 刪除並搬到另一個 topic 或是直接刪除,以減少系統資源的浪費。
在使用兩台大平的 queue service 之前,我們也有透過 self-hosting 開發自己的 queue,例如:beanstalkd, Apache Kafka,但往往專案上線後,都會發現現 self-hosting 的服務難以維運 (畢竟我們不是像 LinkedIn 等等的大公司,無法投入許多人力資源研究) 或是發生效能的問題不好找到解決的方法。
建議在考慮類似解決方案時,可以多利用 cloud service,好處是可以不用管理機器減少維運的成本、避免再造輪子,當真的發生無法解決的問題時,還可以發 support ticket 取得原廠的支援。
• https://cloud.google.com/pubsub/docs/overview • https://cloud.google.com/docs/compare/aws/application-services • https://aws.amazon.com/tw/sqs/details/ • https://www.schibsted.pl/blog/choosing-best-aws-messaging-service/ • https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-dead-letter-queue.html • https://tachingchen.com/tw/blog/google-cloud-pubsub-introduction/ • https://cloud.google.com/pubsub/docs/subscriber#pull-subscription • https://cloud.google.com/nodejs/docs/reference/pubsub/0.18.x/v1.SubscriberClient#modifyAckDeadline
(本文來自合作部落客 Levi Chen:Always Improve Yourself,GCP 專門家授權轉載。)
閱讀更多: