首頁 > 科技

負載測試的端到端指南

2021-06-30 10:02:10

眾所周知,功能性測試通常著眼於單個使用者對於目標應用程式的基本使用體驗。而對成百上千的使用者同時訪問目標站點的場景,特別是那些面向公眾服務的Web應用,開發人員勢必需要在應用上線之前,模擬真實的併發訪問情況,並通過考慮和進行負載測試,為任何可能發生的問題與意外,做好充分的準備。

在本指南中,我將通過如下四個階段,向您介紹負載測試過程中的相關知識。

  • 計劃:為何要測試?測試什麼?

  • 編寫測試指令碼:如何測試?

  • 執行:針對應用程式運行測試指令碼。

  • 分析和報告:發現了什麼?需要修復什麼?

計劃負載測試

在計劃階段,團隊會聚到一起,討論並確定包括目標、範圍、所需資源、以及測試場景等方面的內容。此階段的可交付成果為測試計劃。不過,它在形式上是否正式,則取決於團隊的實際要求。值得注意的是,任何測試計劃都是一項團隊活動,我們需要從所有利益相關者(即:參與測試或可能受測試影響的任何人)處獲取建議。

要求

我們需要搞清楚為什麼要做負載測試?該問題看似簡單,但是不同的利益相關者可能會給出不同的測試場景需求。因此為了達成一致,我們最好將負載測試的目標表述為非功能性的需求 (nonfunctional requirements,NFR),以便定義應用程式的期望狀態,並且能夠包括由團隊決定的效能閾值。例如:基於響應時間的要求,已註冊的使用者登入用時不應超過3秒(即達到90%的響應時間)。可見,好的需求往往能夠滿足:SMART(具體的Specific、可衡量的Measurable、已商定的Agreed Upon、可實現的Realistic、以及及時的Timely)等特點。而且在實踐中,我們可以從如下方面進行把控。

範圍

約定了負載測試的共同目標,我們不但可以縮小待測內容的領域,還能確保每個成員都清楚有哪些部分不需要被測試。

先決條件

在開展測試之前,我們需要考慮包括:參與的人數、執行測試所需的時間、以及測試資料的環境要求等多方面的資源與先決條件。雖然我們並不總是需要一個單獨的測試環境,來進行負載測試,但是如果需要的話,應該事先知會DevOps等團隊。

負載建模

負載模型可以被用來描述模擬負載的一組特徵。例如:使用者最常訪問的是哪些頁面、哪個服務部分、最長訪問的時段與地理位置等方面。您可以將這些因素植入測試指令碼中,以更加真實地模擬出,可能對應用程式產生的流量和影響。

伺服器監控

在測試過程中,我們往往需要通過指令碼,來監控後臺伺服器上各類警報與日誌。如果您的負載測試工具檢測到明顯的效能下降,則需要能夠通過關聯伺服器上的相應資訊,來予以勘察。不過,值得注意的是,任何類型的監控都會增加現有服務資源的開銷,因此整個團隊應事先確定好需要監控和跟蹤的指標與資訊。

測試場景

待測試和模擬的場景設定,往往能夠協助我們更加準確地獲取網站與應用的真實效能。例如:我們既可以創建一個典型工作日的負載配置檔案,又可以模擬大促時的峰值負載配置檔案,還可以模擬某個生產出現中斷時的場景。不同的測試場景能夠為我們採集到的諸如:持續時間、併發使用者數、請求數、激增週期(即:應用從0個使用者上升到最大使用者量的速度)、以及「峰谷」負載(即:在整個測試過程中,每秒請求數的波動)等,可供分析的參數資料。

在設計負載測試計劃時,您既可以包含多條使用者故事線,又可以使用各種Trello卡片(譯者注:一種卡片式任務管理工具)。工具的輸出格式並不重要;重要的是每個成員都能夠從中解讀出一致性、規範化的測試結果。

編寫測試指令碼

有了在前面計劃階段的各項準備,現在我們便可以開始通過編寫負載測試指令碼,來為測試的實施做好準備了。

工具的選擇

目前,市場上有著許多負載測試類工具。出於對各種在用工具、以及財務和供應商等方面的考量,我們不一定可以自由地按需選擇負載測試工具,但是如下方面還是值得我們認真考慮的:

資源和成本

  • 整體購置的價格,及其定價模型是否允許使用者按需增減使用量?

  • 實際需要自行構建,還是應當購買端到端的負載測試方案?

  • 團隊擁有哪些技術技能與工具經驗?誰將負責進行測試?

特點

  • 負載測試工具是否能夠支援應用程式所使用的協議和技術?

  • 測試工具與對應指令碼語言的學習曲線是否「陡峭」?

  • 測試工具是否可以讓多人輕鬆地協作,並處理同一個指令碼?

  • 能否與測試棧中的其他可用於測試管理、測試結果分析、伺服器監控、團隊溝通等工具相整合?

  • 測試工具能否被新增到CI/CD管道中?

  • 該工具是否通過提供簡單的方法,來設定效能閾值或服務等級目標(SLO)?

  • 測試結果能否顯示在可用的報告中,以及能否與現有的資料視覺化工具相整合?

支援

  • 如果出現問題,客戶支援是否需要通過額外付費才能獲取?

  • 線上幫助文件是否夠用?

  • 是否擁有經驗分享的使用者社群?

擴展負載測試

  • 單個負載生成器每秒可模擬多少個虛擬使用者或請求?

  • 能否處理由測試所產生的大資料量?

  • 能否根據使用者的位置特徵,從不同的地理位置實施測試?

  • 是否允許使用者從雲端生成負載?

鑑於上述需求,我選定k6作為開發負載測試指令碼的工具。總的說來,k6有著如下三方面的優勢:

  • 由於它是開源的,因此任何人都可以下載該工具,並親自試用其指令碼。

  • 由於是用JavaScript編寫而成,因此那些使用過Cypress、Puppeteer或Playwright等工具的前端開發人員、或測試人員都能夠輕鬆地上手。

  • 由於它能夠在一臺機器上生成上萬個使用者的併發數,因此即便在負載增加的情況下,它也具有一定的成本效益。

當然,下面將要討論到的各個步驟也適用於其他工具。而且,我強烈建議您使用多種工具,自行進行概念驗證,以找到最適合特定情況和測試場景的工具。

安裝和設定

如果您使用的是Mac系統,那麼便可以使用Brew來輕鬆地安裝k6,即:從終端處運行--brew install k6,就能夠在幾秒鐘之內搞定。

一個基本的k6測試指令碼

如下JavaScript程式碼段展示了最基本的k6測試指令碼:

import http from ‘k6/http’;   export default function () {     let response = http.get(‘https://test.k6.io’);   }

該指令碼會向一個簡單的測試站點發送一個HTTP的GET請求。請將該程式碼複製到文字編輯器中,並存為test.js檔案。接著,您便可以使用命令--k6run test.js,來運行它,並得到如下顯示結果:

在k6中運行簡單的本地測試示例

從上述截圖中,我們可以看出,本地主器上的1個虛擬使用者執行了1次指令碼的迭代。而該HTTP測試請求的響應時間為128.2毫秒(即:http_req_duration)。

使測試指令碼更加真實

顯然,上述指令碼的GET請求過於簡單,無法達到用負載測試指令碼在數量、以及地理分佈上模擬真實使用者的訪問情況。而如果負載測試指令碼不夠真實,則會在測試期間產生誤報,甚至無法讓使用者發現應用元件潛在的效能問題。下面,我們來討論一下如何讓測試指令碼更為真實。

新增靜態資源

如果頁面上帶有可被瀏覽器自動檢索到的影象或指令碼等靜態資源,那麼請確保測試指令碼也會去檢索此類資源。畢竟它們會影響到您獲得頁面的響應時間。當然,如果您已經獲得了來自第三方提供商的許可,那麼您也可以考慮從第三方處獲取靜態資源。

設定快取和cookie行為

雖然站點的首次訪問者無法呼叫本地的快取資源,但是重複訪問者則會從快取中檢索相應的資源。對此,我們應當檢查負載測試工具的預設快取和cookie管理的設定,並通過按需更改,來匹配真實的測試場景。

新增「思考時間」

真正的使用者通常不會不停地反覆重新整理相同的URL。他們在導航到目標網站後,會花一些時間閱讀頁面上的內容,與頁面上的某些元件進行互動。這些使用者的「思考」時間其實就是各個請求之間的延遲。因此,通過新增1到5秒的「思考時間」,我們可以讓應用伺服器免於遭受外掛機器人發出的請求轟炸。

使用不同的使用者路徑

使用者路徑是指使用者如何與應用程式進行互動的流程,其中包括:他們會訪問哪些頁面,輸入哪些資訊等。我們前面在計劃階段所建立的工作負載模型,可以直接反映出系統中最常見的使用者流程,例如:使用不同的瀏覽器進行登入,或是從購物車中選擇商品付款等。在k6中,我們可以通過新增不同的場景來實現,而其他工具則可能稱之為執行緒組或執行組。

新增測試資料

正如普通使用者是不會一遍又一遍地搜尋相同的關鍵字,也不會使用同一個測試帳戶在各處同時登入那樣,我們的測試指令碼也不應該重複地使用相同的資料。如果多個虛擬使用者使用同一帳戶進行登入,那麼就可能導致其響應被快取,進而縮短響應的時間,或增加錯誤率。對此,您需要將指令碼修改為從某個CSV檔案中獲取測試資料,以增加真實的隨機性。

設定測試參數

測試參數往往能夠通過調整測試使用者數的激增與驟降,來改變使用者負載的時間變化趨勢,進而協助您繪製出虛擬使用者數與時間變化的曲線圖表。

在k6中體現的負載測試期間虛擬使用者的數量變化

設定失敗的判定標準

模擬真實使用者的一個重要環節便是發現有哪些因素會導致使用者訪問的失敗。您可以通過新增響應驗證、檢查和閾值(包括響應時間或錯誤率的閾值),將失敗的判定標準新增到測試指令碼中。同時,您也可以根據實際情況,靈活地調整這些與效能相關的標準。

根據上述討論的要點,我對最初的k6基本指令碼進行了修改,讓它更貼近真實的測試情況。

執行負載測試

讓我們延用上面的k6指令碼,並通過執行如下命令,來觸發負載測試的運行:

k6 run test.js

該命令將根據檔案中已有的測試參數在本地執行k6指令碼。此類小型驗證性測試,通常被稱為震盪測試(shakeout tests)。當然,我們接下來會在基礎架構上運行更加複雜的負載測試。

測試的真實性

當您在資料中心的主機上運行負載測試時,由於測試與應用伺服器同屬一個網路,其響應時間會比使用者真實體驗到的要快得多。因此,我們應當設法將負載生成器的位置,與使用者的物理位置相匹配。對此,在雲端運行測試便是一種增加測試真實性的簡便方法,尤其是當您的大多數終端使用者是在組織外部的時候。

針對上述例子,您可以通過連結--https://app.k6.io/account/register,註冊一個k6的雲端帳戶(其中,前50個測試是免費的)。由於k6本身是開源的,因此您也可以在自己的雲端基礎設施上運行它。當然原生的k6雲服務會更加直接且便於上手。

在擁有了帳戶之後,您可以通過連結--https://app.k6.io/account/api-token,複製API令牌,然後在終端中運行如下命令,以授權本地的k6運行您的帳戶:

k6 login cloud –token

而成功地通過了身份驗證之後,您便可以選擇在雲端運行如下命令了:

k6 cloud test.js

下圖展示了k6執行的負載測試結果。圖中的執行模式(execution)則表明您是在雲端運行該測試的。

由於您的測試預設會在美國Ashburn區域的k6 AWS賬戶中運行,因此您可以使用雲端執行選項(cloud execution options,),將此設定按虛擬使用者的比例,指定到其他區域。

分析負載測試的結果和報告

儘管我們在邏輯上會將分析流程與執行步驟相互分離,但是兩者實際上是重疊的。也就是說,上述k6的輸出截圖中其實已經包含了指向k6雲端儀表板的連結,可方便我們在測試運行過程中,實時地檢視到測試的結果。這種實時監控的測試方式可以讓使用者在出現問題時,及時地發現問題,並在必要時中止測試,以對其進行修復。如果測試是由多個負載生成器來執行的,那麼k6會有一個統一的儀表板,以展示測試的整體概況。

在k6Cloud中執行負載測試後的結果示例

如果出現大量的錯誤,或者是響應時間明確地表明某個元件無法處理負載的情況,我們應當立即中止測試,獲取必要的資訊,以針對出現的瓶頸提出效能改進和解決方案。當然,k6也會幫助使用者創建指向儀表板的可共享式連結,以方便相關團隊通過協同「會診」,發掘出測試資料背後的真實原因。

雖然這些帶有測試結果的共享儀表板足以滿足敏捷團隊,但是對於某些項目而言,則可能需要正式的測試記錄總結報告。畢竟,負載測試的目的並不在於測試本身,而是對於結果的處理。我們需要向利益相關者清楚地傳達測試結果,以便大家更為有效地解決各種效能問題。


IT145.com E-mail:sddin#qq.com