Google 的基礎架構旨在以高規模彈性運作:大多數層級都能因應流量需求增加,擴充至龐大規模。其中一個核心設計模式是適應性層,也就是基礎架構元件,可根據流量模式動態重新分配負載。不過,這項調整需要時間。由於使用 Cloud Tasks 可分派非常龐大的流量,因此如果流量增加速度快過基礎架構能應付的速度,就會為實際工作環境帶來風險。
總覽
本文提供在高流量佇列中維持高 Cloud Tasks 效能的最佳做法指南。高 TPS 佇列是指每秒建立或分派 500 個以上工作的佇列 (TPS)。高 TPS 佇列群組則是指一組連續的佇列 (例如 [queue0001、queue0002、…、queue0099]),其中總共建立或分派了至少 2000 個工作。如要查看佇列或佇列群組的 TPS 記錄,您可使用 Stackdriver 指標、api/request_count
(「CreateTask」作業數) 和 queue/task_attempt_count
(工作嘗試次數)。高流量的佇列與佇列群組可能會出現兩種不同的失敗情形:
佇列超載是指工作建立或分派到個別佇列或佇列群組的速度,快過佇列基礎架構能調整因應的速度。同樣地,如果工作分派速率導致下游目標基礎架構的流量暴增,就會發生目標超載。在上述兩種情況下,建議您遵循 500/50/5 模式:當擴展超過 500 TPS 時,每 5 分鐘增加的流量不得超過 50%。本文將檢視可能出現資料調度風險的各種情境,並提供範例來說明如何套用這個模式。
佇列超載
任何流量遽增的情形都可能造成佇列或佇列群組超載,導致佇列發生下列情形:
- 工作建立作業延遲時間增加
- 工作建立作業錯誤率提高
- 分派速度降低
為防範這種情況,建議您在佇列或佇列群組的建立或調度率可能突然飆升時,建立控管機制。建議傳送至冷佇列或佇列群組的流量不要超過每秒 500 項作業,接著每 5 分鐘增加 50% 的流量。理論上,這種增幅時程能在 90 分鐘後達到每秒處理 740K 個作業的速率。發生這種情況的原因有很多。
例如:
- 推出需要大量使用 Cloud Tasks 的新功能
- 在佇列間移動流量
- 在佇列增減後重新平衡流量
- 執行批次工作來置入大量工作
在這些情況或其他情況下,請按照 500/50/5 的模式操作。
使用 App Engine 流量拆分功能
如果這些工作是由 App Engine 應用程式建立,您可以利用 App Engine 流量拆分功能 (標準/Flex) 應付流量增加的情況。將流量拆分為兩種版本 (標準/Flex),可讓需要速率管理的要求隨時間進行轉移,以維持佇列的良好狀態。舉例來說,假設要將流量導入新擴充的佇列群組:[queue0000、queue0199] 是一連串高 TPS 佇列,尖峰時段總共會收到 100,000 個 TPS 建立作業。
[queue0200, queue0399] 是新佇列序列。在所有流量都已轉移後,序列中的佇列數會加倍,而新的佇列範圍會接收 50% 的序列總流量。
部署會增加佇列數的版本時,請使用流量拆分功能將流量逐步轉移到新的版本,然後再轉移到新的佇列。
- 首先轉移 1% 的流量到新版。例如 100,000 TPS 的 1% 再 50% 會得出有 500 TPS 轉移到新版。
- 每 5 分鐘的增幅為傳送到新版流量的 50%,詳細說明請見下表:
自部署開始以來的分鐘數 | 佔轉移到新版總流量的百分比 | 佔新佇列總流量的百分比 | 佔舊佇列總流量的百分比 |
---|---|---|---|
0 | 1.0 | 0.5 | 99.5 |
5 | 1.5 | 0.75 | 99.25 |
10 | 2.3 | 1.15 | 98.85 |
15 | 3.4 | 1.7 | 98.3 |
20 | 5.1 | 2.55 | 97.45 |
25 | 7.6 | 3.8 | 96.2 |
30 | 11.4 | 5.7 | 94.3 |
35 | 17.1 | 8.55 | 91.45 |
40 | 25.6 | 12.8 | 87.2 |
45 | 38.4 | 19.2 | 80.8 |
50 | 57.7 | 28.85 | 71.15 |
55 | 86.5 | 43.25 | 56.75 |
60 | 100 | 50 | 50 |
版本導向的流量遽增情形
推出會大幅增加佇列或佇列群組流量的版本時,逐步推行同樣也是順利增加流量的重要機制。逐步推行執行個體,讓初始推行到新佇列的作業不會超過 500 個,且每 5 分鐘的增幅不超過 50%。
新的高 TPS 佇列或佇列群組
新建立的佇列特別容易遭受安全攻擊。舉例來說,[queue0000、queue0001、…、queue0199] 的佇列群組在初始推行階段也跟單佇列同樣敏感。對於這些佇列來說,逐步推行是相當重要的策略。請分階段推行會建立高 TPS 佇列或佇列群組的新服務或更新服務,讓初始負載低於 500 TPS,且每 5 分鐘 (或更長的時間間隔) 的分階段增幅不超過 50%。
新擴展的佇列群組
增加佇列群組的總容量時,例如將 [queue0000-queue0199] 擴展為 [queue0000-queue0399],也請按照 500/50/5 的模式操作。請務必記住,就推行程序而言,新的佇列群組與個別群組並無差別。請將 500/50/5 的模式套用到整個新群組,而非只是群組中的個別佇列。對於這些佇列群組擴展作業而言,逐步推出同樣也是相當重要的策略。如果流量來源為 App Engine,則可使用流量拆分功能 (請參閱版本導向的流量遽增情形)。藉由遷移服務將工作新增到增加的佇列時,請逐步推行執行個體,讓初始推行到新佇列的作業總共不超過 500 個,每 5 分鐘的增幅不超過 50%。
緊急佇列群組擴展
有時您可能會想要擴展現有的佇列群組,例如工作新增到佇列群組的速度,預期會超過群組分派速度等情形。如果依字典順序排序時,新佇列名稱平均分布在現有佇列名稱之間,只要交錯的新佇列不超過 50%,且每個佇列的流量低於 500 TPS,即可立即將流量傳送到這些佇列。這個方法可替代上述章節所述的流量拆分和逐步推出功能。
在佇列結尾附加偶數數字的後置字串可達成這種類型的插入命名作業。舉例來說,如果您有 200 個現有佇列 [queue0000-queue0199],然後想要建立 100 個新佇列,請選擇 [queue0000a, queue0002a, queue0004a, …, queue0198a] 做為新佇列名稱,而非 [queue0200-queue0299]。
如果還要新增佇列,您仍可以採用每 5 分鐘插入不超過 50% 佇列的方法。
大規模/批次工作排入佇列
如需新增幾百萬或幾十億之類的龐大工作量時,可使用雙重插入模式。相對於從單一作業建立工作,請使用插入程式佇列。每個新增到插入程式佇列的工作都會擴散傳遞,並將 100 個工作新增到所要佇列或佇列群組。插入程式佇列可隨時間加快速度,例如從 5 TPS 開始,然後每 5 分鐘增幅 50%。
命名工作
建立新工作時,根據預設,Cloud Tasks 會指派一個不重複的名稱給工作。您可以使用「name」 參數為工作指派自訂名稱。不過這會對效能造成大量負擔,加重延遲情形,且可能會提高命名工作相關的錯誤率。如果工作名稱採循序方式 (例如附有時間戳記),則這些成本還可能會大幅增加。所以,如果您自行指派名稱,建議您在工作名稱中使用分佈均勻的字首,例如內容的雜湊。請參閱說明文件,進一步瞭解如何為工作命名。
目標超載
如果佇列在短時間內大幅增加調度作業,Cloud Tasks 可能會造成您使用的其他服務過載,例如 App Engine、Datastore 和網路用量。如果累積了待處理工作,那麼將這些佇列取消暫停,可能就會產生上述的超載服務情形。如同針對佇列超載所給予的建議,我們同樣也推薦您採取 500/50/5 模式防範這種情況:如果佇列分派速度超過 500 TPS,請增加由佇列觸發的流量,每 5 分鐘增幅不超過 50%。請使用 Stackdriver 指標主動監控增加的流量。Stackdriver 提醒可用於偵測可能的危機狀況。
取消暫停或恢復高 TPS 佇列
取消暫停或重新啟用單個佇列或連續佇列時,佇列會繼續執行分派作業。如果佇列中的工作很多,則剛啟用的佇列進行分派的速度可能就會從 0 TPS 遽增到佇列的完全容量。為了提升處理能力,交錯佇列會使用 Cloud Tasks 的 maxDispatchesPerSecond
恢復或控管佇列分派速率。
大量排定的工作
排定同時分派的大量工作也有可能帶來目標超載的風險。如果您需要同時啟動大量工作,請考慮使用佇列速度控管來逐步提高分派速度,或事先明確轉移目標容量。
增加擴散傳遞
更新透過 Cloud Tasks 執行的服務時,增加遠端呼叫數可能會讓實際工作環境遭受風險。舉例來說,假設高 TPS 佇列中的工作會呼叫處理常式 /task-foo
。舉例來說,如果新版本在處理常式中新增了多項耗費資源的 Datastore 呼叫,可能會大幅增加呼叫 /task-foo
的成本。這類版本直接帶來的結果,可能就是 Datastore 流量暴增,然後立即反映在使用者的流量變化上。請採用逐步推行或流量拆分功能來管理流量遽增情形。
重試
進行 Cloud Tasks API 呼叫時,程式碼會在發生失敗時重試。不過,當有大量要求因為伺服器端錯誤而發生失敗時,高比例的重試作業可能會加重佇列的超載情形,導致佇列需要更久時間復原。因此,如果用戶端偵測到有相當比例的要求因伺服器端錯誤而失敗,建議您限制傳出流量,例如使用《網站可靠性工程》一書「處理過載」一章所述的自適應節流演算法。Google 的 gRPC 用戶端程式庫可實作這個演算法的變化版本。