關於實作秒殺壓力測試的架構驗證
之前為了一個案子,實作了一個POC秒殺的情境,透過python、nginx、lucust、docker來模擬,但那時候必竟是架構新手,對於POC驗證的環節
只想的到以下的方式,以下提供參考…若有盲點或不足之處,歡迎指導…
一 測試內容
二 測試方法
三 測試方法
四 測試目標
五 測試環境
5-1 壓力測試部署圖
5-2 壓測用戶端與服務端主機規格
六 系統部署
6-1 系統部署架構圖
6-2相關系統容器配置表
七 性能測試結果與分析
7-1 測試步驟與結果摘要
7-2 劇情1 線上用戶30,000,開放10,000個號碼牌
7-3 劇情2線上用戶30,000,開放30,000個號碼牌
7-4 結果與發現
一 測試內容
本次測試是針對搶票系統進行壓力測試,在秒殺產品的場景中,需求遠遠大於供給,因此考慮巨大流量的情況下,我們在設計交易的接口中,加入了號碼牌機制,從入場、選位到結帳三關卡皆透過號碼牌的控制來監控與管理入場選擇產品的人流。並逐步縮小對於後端API的請求,達到集中運算資源與降低關鍵接口負載壓力的目的。這次我們主要驗證的功能包含了領取號碼牌、選位與結帳的功能。
二 測試方法
本次採用了python開源的分散式壓力測試工具Locust.io,這個工具的特性是可以快速佈署壓測用戶端的集群,並透過統一的Master發動壓力測試,並具備Dashboard,提供效能統計表與分析圖型,近期Amazon Web Service廠商已經善用其可分散式佈署的特性,透過259台用戶端,將壓力測試提升到每秒超過10萬次的後端請求的等級,請參考相關AWS官方連結。
這次測試採用容器技術動態建立Locust測試集群,並透過Http協議發出GET請求,伺服器端主要透過Nginx+Tornado建立Load Balance與非阻塞式的Web Server,並結合容器技術動態擴充WebServer群,包含主要關鍵流程API,包含取得號碼牌請求、模擬選位請求、模擬結帳請求。關鍵流程之間,透過Redis快取技術協調並模擬用戶狀態(包含入場前、入場選位前、選位後、結帳前),最終透過MongoDB儲存持久化交易結果。
三 測試場景
測試場景包含了1取得號碼牌API,其主要目的是第一關控制流量,但也因為要面對第一線最多的請求流量,因此需要的資源最多。其2為模擬選位API,因應用戶取得號碼牌後的狀態變動,我們透過快取保存用戶狀態,以模擬用戶端行為。用戶在具備號碼牌的狀態下,呼叫模擬選位API,會有自動配位的邏輯處理,亂數決定客戶購買1~4張的張數,並動態查詢仍有空位的連續座位區域並隨機決定。此時會透過鎖定機制,保存在快取內,並非同步創建訂單到NoSQL的儲存體中,其狀態為未付款(Pay Status=1),並將此用戶加入到待付款的佇列中。最終為模擬結帳API,此API將會隨機取得佇列中的排隊付款用戶,並同步更新NoSQL的付款狀態(Pay Status=2),此時會標記其用戶已付款完成。
本次測試樣本將模擬銷售單一場次、6區域,依2回合進行測試,分別開放token限制為1萬、3萬,分別模擬請求流量的變化。
四 測試目標
測試獲取單一物理主機的伺服器在反應時間3秒內,其單位承載量RPS為多少,模擬併發用戶為多少。
採用號碼牌分流搶票流程下,在上述系統效能需求下,最終全數票券銷售完成到結帳狀態(模擬完成金流後,寫回訂單資料押付款完成的狀態)需要多久的時間。
五 測試環境
5-1 壓力測試部署圖
5-2 壓測用戶端與服務端主機規格
環境 | 機器型號 | 作業系統 | 硬體cpu | 硬體mem |
用戶端 | Linux虛擬機 | CentOS 7 | 4核 | 8G |
服務端 | Linux虛擬機 | CentOS 7 | 4核 | 8G |
六 系統部署
6-1 系統部署架構圖
6-2相關系統容器配置表
容器環境 | 佈署應用程式 | 數量# | 備註 |
用戶端主機 | Locust Master | 1 | 統一發動測試端與測試結果Dashboard |
Locust Slave | 10 | 接受發動測試指令,執行測試腳本 | |
服務端主機 | Nginx | 3 | 用於3個關鍵流程的Reverse Proxy分流關卡 |
Tornado(Token API) | 5 | 主要面對最大流量領取號碼牌請求 | |
Tornado(Reserve API) | 3 | 面對已過濾擁有號碼牌的用戶進行選位模擬 | |
Tornado(Admin API) | 1 | 初始化資料預熱
Dashboard監控資訊 開放TokenLimit接口 |
|
MongoDb(NoSQL) | 1 | 主要儲存最終訂單持久化與結帳後模擬金流回填狀態。 | |
Redis Cache Server | 1 | 主要處理關鍵流程間狀態控管 |
七 性能測試結果與分析
7-1 測試步驟與結果摘要
步驟一.Dashboard 初始化
步驟二.Locust配置與啟動
步驟三.抽樣觀測Server狀態與銷售狀態
步驟四 銷售完畢後,並待所有結帳佇列消耗完成後,搜集Client端數據
7-2 劇情1 模擬線上30,000用戶,開放10,000個號碼牌,銷售總票數為10,000張
7-2-1 Locust壓測用戶端統計資訊
開放10,000個號碼牌,銷售總票數為10,000張 | |
模擬線上用戶數 | 30,000 |
用戶平均爬升數/秒 | 2,000 |
銷售總花費時數 | 1分40秒 |
有效訂單數(已付款,已進入數據庫) | 3,971 |
總請求數(擷至全售完) | 117,678 |
總平均RPS(Request per Second) | 1,176.8 |
取號碼牌成功請求總數(HttpStatus=200) | 32,268 |
模擬選位成功請求總數(HttpStatus=200) | 10,903 |
模擬結帳成功請求總數(HttpStatus=200) | 7,610 |
服務器狀態 | 全數存活 |
7-2-2 Locust壓測期間趨勢圖
7-2-3容器正常服務
7-3 劇情2 模擬線上30,000用戶,開放20,000個號碼牌,銷售總票數為10,000張
7-3-1 Locust壓測用戶端統計資訊
開放20,000個號碼牌,銷售總票數為10,000張 | |
模擬用戶數 | 30,000 |
用戶平均爬升數/秒 | 2,000 |
銷售總花費時數 | 2分17秒 |
有效訂單數(已付款,已進入數據庫) | 3,962 |
總請求數(擷至全售完) | 156,029 |
總平均RPS(Request per Second) | 1,138.9 |
取號碼牌成功請求總數(HttpStatus=200) | 36,606 |
模擬選位成功請求總數(HttpStatus=200) | 14,776 |
模擬結帳成功請求總數(HttpStatus=200) | 6,984 |
服務器狀態 | 全數存活 |
7-2-2 Locust壓測期間趨勢圖
7-2-3容器正常服務
7-4 結果與發現
從相同的壓測用戶參數,並透過號碼牌來控制流程API的流量,我們發現號碼牌發放的控制,可以有效提升服務效率,銷售的時間更短。同時,這次銷售10,000張票在我們配置的架構下(Nginx與Tornado),單台主機可以支撐爆量請求而不會造成應用程式崩潰與異常銷售,仍然可以將其票券全數售完,並正常寫入資料庫。而本次透過容器建置所有的系統與API,說明未來管理上雲或是自建機房(IDC)可以在即短的時間內佈署。同時具備易用與易於擴充的特性。而切分微服務的概念,除了在系統佈署的配置上可以更彈性的運用,且未來更有機會隨時提升到Serverless的層次,透過雲端全託管的服務,可以有效降低維運成本。