爲迎接“黑五”流量,我們是如何做準備的?

如果你是一家實體企業的老闆,很快就會發現客流量模式(尤其是在節假日期間),實現銷售目標依賴於你提供及時而優質的服務。如果你是一家網店的老闆,就像Curalate的1000多名客戶一樣,也並沒有什麼不同:假日期間的銷售對成功來說至關重要,而它們在很大程度上取決於網站的可靠性。

在Curalate,我們爲能夠全年保持客戶集成的高可用性和低延遲而感到自豪。在“黑色星期五”期間以及聖誕節前一週和聖誕節之後的幾天,來自客戶站點對我們API的請求量增加了大約5倍。我們的系統需要能夠處理增加的負載,並提前對系統進行負載測試,以證明我們的系統設計是有效的。

這篇文章描述了我們如何對基礎架構進行負載測試,以應對假日流量對我們的API帶來的衝擊。此外,我們還介紹了動態伸縮方法是如何通過避免過度配置來降低成本的。

負載測試計劃

我們的第一個問題是:我們的預期流量是多大?爲了回答這個問題,我們查閱了過去幾年的假日流量數據。第二個問題:流量有哪些重要的特徵?例如,大部分流量是使用緩存還是不使用?是總請求量重要還是瞬時負載更重要?由於之前的一篇文章已經討論了緩存與未緩存的測試,因此本文將重點介紹API請求率。

一天的總請求量只表明了平均每秒請求數(RPS),而我們更感興趣的指標是日RPS峯值。它可以讓我們瞭解一天中最繁忙的時刻,如果我們能夠應對這個時刻的請求速率,那麼就應該有信心處理其他時間段較低的請求速率。

每秒請求峯值

通過查詢歷史數據,我們發現,黑色星期五的日RPS峯值通常比同年9月的正常峯值高5倍。因此,我們基於2018年9月的數據計算出了5倍RPS峯值,然後使用了一些簡單的bash腳本和其他工具來穩定地將API請求負載增加到預測的最大速率。

下圖顯示了我們的API在整個第四季度(2018年9月至12月)期間的日RPS峯值。其中11月5日顯示了使用以下腳本生成的內部負載(目標是預期的5倍流量)。11月24日(黑色星期五)和12月5日是最終用戶生成的API流量的兩個峯值。

我們的預測完全正確!事實上,我們並沒有期望預測能夠接近準確的峯值流量負載,或許我們還可以測試高一點的負載。

執行負載測試

我們已經在2017年的一篇有關假期流量負載測試的文章中分享了我們執行的不同負載測試(緩存和未緩存、各種API端點等),並提供了一些示例輸出。因此,現在這裏只提供其中的一個腳本。爲了執行實際的負載測試,我們今年再次使用了Vegeta,因爲去年用過它,對它感到很滿意。

以下的bash腳本顯示了我們如何使用Vegeta逐步增加對指定API端點的請求率:

#!/bin/bash

#  File: load-test.sh
# usage: ./load-test.sh <api endpoint> <start rate> <rate step increment> <step duration> <max rate> <test tag>

if [ $# -ne 6 ]; then
  echo "usage: $0 <api endpoint> <start rate> <rate step increment> <step duration> <max rate> <test tag>"
  exit 1
fi

Target=$1
StartRate=$2
RateStep=$3
StepDuration=$4
MaxRate=$5
Tag=$6

CurrentRate=$StartRate

while [ $CurrentRate -le $MaxRate ]; do
  OutputFile="test-$Tag-$MaxRate-$CurrentRate.bin"
  if [ $CurrentRate -lt $MaxRate ]; then
    echo $Target | ./vegeta attack -rate=$CurrentRate -duration=$StepDuration > $OutputFile
  else
    echo $Target | ./vegeta attack -rate=$MaxRate > $OutputFile
  fi
  CurrentRate=$((CurrentRate+RateStep))
done

上面的腳本將重複執行Vegeta,逐步增加請求率,直到達到指定的最大速率。每次Vegeta將運行指定的持續時間,最後一次(達到最大速率)將會一直運行,直到被手動終止。此外,每次執行都會生成一個不同的Vegeta輸出文件。

彈性縮放示例

處理日流量負載的5倍峯值其實非常簡單,對吧?

InstanceCount=$(echo "$InstanceCount * 5" | bc)

如果不考慮成本,這真的很容易。但對於關心成本的人來說,我們的目標是隨着對服務需求的增加動態擴展計算資源,然後隨着需求的減少優雅地縮減資源。

動態縮放

顯然,只要配置得當,AWS會使這一切變得非常容易。我們的一些遺留服務仍然作爲AMI運行(部署在EC2實例的自動伸縮組中),不過大多數微服務現在作爲容器運行在Amazon ECS上。今年早些時候,我們寫了一篇文章,詳細介紹了在ECS上運行我們的生產系統時所涉及的各個方面。

由於之前的文章已經解釋了我們如何在ECS上運行我們的系統,所以這篇文章只提供一個動態縮放的例子。下圖顯示了我們的一項叫作“Media API”(“media-api-service”)的服務請求率,以及從聖誕節到12月27日三天期間爲該服務提供的相應容器數量(“media-api-service_v3”)。

我們快速添加了更多的容器來滿足不斷增長的請求需求,在請求率下降後又很快移除它們。雖然下方的圖並不能直接表示底層EC2實例的數量變化情況,但如果集羣中的所有服務都採用類似的擴展方法,那麼它可以很好用來估計EC2的動態容量(和成本)。

縮放指標

說到縮放,我們需要度量哪些指標?我們可以考慮CPU和內存利用率,以及延遲和隊列大小。根據我們的經驗,CPU利用率的伸縮對於基於容器的服務來說已經足夠好了。當給定服務的容器平均CPU利用率超過某個閾值(比如75%),我們就添加一個新容器,並在一段時間後重新計算。當CPU利用率下降到60%以下時,我們停止一個容器,並在一段時間後重新計算。我們以相同的方式基於內存使用率來伸縮服務。

討論和相關說明

爲了簡潔起見,這篇文章跳過了與上述各方面相關的幾個點。接下來讓我談談一些值得注意的問題和相關細節,雖然它們不是這篇文章主題的核心。

  1. 雖然總請求量不直接描述每秒峯值請求,但它可能會影響對總數據大小比較敏感的其他資源,例如事件隊列和日誌記錄/診斷數據。在執行負載測試和麪對增加的實時流量時,請將這些類型的資源考慮在內。
  2. 我們討論了擴展計算資源以滿足增加的服務請求率,但如果你的流量出現極端的突發(例如在幾秒鐘內從1倍變爲10倍或更高),那麼你應該考慮使用CDN而不是動態伸縮。CDN在推送新數據方面引入了一些延遲,但它可以承受更高的請求率,因爲響應是由輸入的請求決定的。
  3. 生產環境基礎設施的綜合負載測試可能會因爲使用了一些資源(比如數據庫、緩存和事件隊列)給實時的生產流量帶來影響。例如,如果你在實時基礎設施上運行“無緩存”測試,可能會將所有真實客戶的數據從緩存中移除,並大幅降低生產流量的性能。
  4. 文章開頭提到了假期服務可靠性的重要性。要了解在2018年黑色星期五期間Curalate與其他幾個競爭對手之間的可靠性對比,請看這篇文章

英文原文:http://engineering.curalate.com/2018/12/31/holiday-load-prep.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章