Jmeter-執行緒組下篇

EtherealBoyJiang發表於2024-05-08

執行緒組

執行緒組作為JMeter測試計劃的核心元件之一,對於模擬併發使用者的行為至關重要。執行緒組元件是整個測試計劃的入口,所有的取樣器和控制器必須放置線上程組下。

可以將執行緒組視為一個虛擬使用者池,其中每個執行緒可被理解為一個虛擬使用者,多個虛擬使用者同時執行相同的一批任務。

在這個虛擬使用者池中,每個執行緒之間是相互隔離且互不影響的。每個執行緒的執行過程中,操作的變數不會對其他執行緒的變數值產生影響。

執行緒組的關鍵任務之一是定義併發使用者的行為,包括設定執行緒數、迴圈次數、啟動延遲等關鍵引數。透過適當配置執行緒組,測試人員可以模擬多使用者在系統中同時執行任務的場景,從而評估系統的效能和穩定性。

透過靈活使用setup執行緒組、執行緒組、tearDown執行緒組、開放模型執行緒組,配置前置操作、主要操作、後置操作,更能真實、詳細的評估系統。

執行緒組分為四類:

  • 執行緒組
  • setUp執行緒組
  • tearDown執行緒組
  • 開放模型執行緒組

執行緒組、setUp執行緒組、tearDown執行緒組控制皮膚中的元素基本一致:

  • 名稱、註釋
  • 在取樣器錯誤後執行的動作
  • 執行緒數
  • Ramp-Up時間
  • Same user on each iteration
  • 延遲建立執行緒直到需要(只有執行緒組有)
  • 排程器

開放模型執行緒組控制皮膚中的元素:

  • 名稱、註釋
  • 在取樣器錯誤後執行的動作
  • 排程計劃
  • 隨機種子

取樣器錯誤後執行的動作


在JMeter中,取樣器(Sampler)是用於模擬使用者請求傳送到目標伺服器的元件,例如HTTP請求、FTP請求等。當取樣器執行過程中出現錯誤時,可以透過配置相應的動作來處理這些錯誤。以下是一些處理取樣器錯誤時,執行緒組中常見方式:

  • 停止執行緒

    任何一個執行緒(使用者)在執行過程中遇到錯誤時,該執行緒被停止,不影響其他執行緒(使用者)。

  • 啟動下一程序迴圈
    任何一個執行緒(使用者)在執行過程中遇到錯誤時,Jmeter會立即停止當前執行緒的本次執行,並進行當前執行緒(使用者)的下次執行,主要應用於執行緒多次迴圈時。

  • 繼續(無需演示)

    JMeter將在取樣器執行錯誤時,忽略錯誤繼續執行本執行緒的後續操作及執行其他執行緒。


停止執行緒-多執行緒


示例介面程式碼

@ThreadGroup.route('/api/ThreadGroup5/', methods=['GET', 'POST'])  
def threadgroup5():  
    return '200'

示例Jmeter指令碼

  • 測試計劃下新增執行緒組

    取樣器錯誤後執行的動作中勾選停止執行緒

    執行緒數3

  • 執行緒組下依次新增2個HTTP 請求取樣器

    名稱:錯誤請求-${yonghu}(在前)、正確請求-${yonghu}

    請求地址:HTTP://127.0.0.1:5000/api/ThreadGroup5/

    請求方式:GET

  • 執行緒組下新增CSV 資料檔案設定(右鍵-新增-配置元件)

    檔名ceshi.txt的路徑

     ceshi.txt檔案內容:(複製後,手動刪除前面的空格)
      200,使用者1
      1111,使用者2
      200,使用者3

    檔案編碼UTF-8

    變數名稱ceshi,yonghu

  • 錯誤請求取樣器下新增響應斷言

    值:${ceshi}

  • 測試計劃中,新增檢視結果樹

image

執行結果

image

連續執行了3次,結果是一致的。總共有三個使用者執行執行緒組,其中使用者1使用者3完全執行成功;使用者2只執行了錯誤請求

因為設定取樣器錯誤後執行的動作停止執行緒使用者2執行錯誤請求時發生錯誤,Jmeter只會停止使用者2的後續執行,不會影響其他執行緒。

多執行緒組也是多執行緒,讀者在實際的指令碼編寫中,要注意每個執行緒的情況去使用停止執行緒


停止執行緒-多迴圈


示例介面程式碼

@ThreadGroup.route('/api/ThreadGroup5/', methods=['GET', 'POST'])  
def threadgroup5():  
    return '200'

示例Jmeter指令碼

  • 測試計劃下新增執行緒組

    取樣器錯誤後執行的動作中勾選停止執行緒

    迴圈次數3

  • 執行緒組下依次新增2個HTTP 請求取樣器

    名稱:錯誤請求-${xunhuan}(在前)、正確請求-${xunhuan}

    請求地址:HTTP://127.0.0.1:5000/api/ThreadGroup5/

    請求方式:GET

  • 執行緒組下新增CSV 資料檔案設定(右鍵-新增-配置元件)

    檔名ceshi.txt的路徑

     ceshi.txt檔案內容:(複製後,手動刪除前面的空格)
      200,第1次迴圈
      1111,第2次迴圈
      200,第3次迴圈

    檔案編碼UTF-8

    變數名稱ceshi,xunhuan

  • 錯誤請求取樣器下新增響應斷言

    值:${ceshi}

  • 測試計劃中,新增檢視結果樹

image

執行結果

image

連續執行了3次,結果是一致的。使用者在第2次迴圈執行到錯誤請求時,Jmeter停止測試。

因為設定取樣器錯誤後執行的動作停止執行緒,使用者的第2次迴圈,執行錯誤請求時發生錯誤,Jmeter停止使用者的後續執行(就它一個執行緒)。


啟動下一程序迴圈


示例介面程式碼

@ThreadGroup.route('/api/ThreadGroup5/', methods=['GET', 'POST'])  
def threadgroup5():  
    return '200'

示例Jmeter指令碼

  • 測試計劃下新增執行緒組

    取樣器錯誤後執行的動作中勾選啟動下一執行緒迴圈

    迴圈次數3

  • 執行緒組下依次新增2個HTTP 請求取樣器

    名稱:錯誤請求-${xunhuan}(在前)、正確請求-${xunhuan}

    請求地址:HTTP://127.0.0.1:5000/api/ThreadGroup5/

    請求方式:GET

  • 執行緒組下新增CSV 資料檔案設定(右鍵-新增-配置元件)

    檔名ceshi.txt的路徑

     ceshi.txt檔案內容:(複製後,手動刪除前面的空格)
      200,第1次迴圈
      1111,第2次迴圈
      200,第3次迴圈

    檔案編碼UTF-8

    變數名稱ceshi,xunhuan

  • 錯誤請求取樣器下新增響應斷言

    值:${ceshi}

  • 測試計劃中,新增檢視結果樹

image

執行結果

image

連續執行了3次,結果是一致的。使用者執行了3次迴圈,其中第2次迴圈中,錯誤請求出現錯誤,跳過正確請求

因為設定取樣器錯誤後執行的動作啟動下一執行緒迴圈,使用者的第2次迴圈,執行錯誤請求時發生錯誤,Jmeter會跳過使用者的本次執行,進行使用者的後續執行。


ramp-up時間


ramp-up時間用於設定啟動所有執行緒所需要的時間。例如:執行緒數設定為10,ramp-up時間設定為100秒,那麼JMeter將使用100秒使10個使用者啟動並執行,即每個使用者將在前一個使用者啟動後的10秒啟動。

如果ramp-up值設定得很小、執行緒數又設定得很大,剛開始執行測試時會對伺服器產生很大的壓力。

示例介面程式碼

@ThreadGroup.route('/api/ThreadGroup5/', methods=['GET', 'POST'])  
def threadgroup5():  
    return '200'

示例Jmeter指令碼

  • 測試計劃下新增執行緒組

    Ramp-Up時間:9

    執行緒數3

  • 執行緒組下新增1個HTTP 請求取樣器

    請求地址:HTTP://127.0.0.1:5000/api/ThreadGroup5/

    請求方式:GET

  • 測試計劃中,新增檢視結果樹

image

執行結果

image

連續執行了3次,結果是一致的。3個使用者執行執行緒組,各個使用者的請求時間分別為2024-04-15 16:12:37 CST2024-04-15 16:12:40 CST2024-04-15 16:12:43 CST

3個使用者執行請求的間隔時間正好是3秒,即ramp-up時間/執行緒數


same user on each iteration(在每次迭代中使用相同的使用者)


沒有研究出來它有什麼用。經過我的測試,same user on each iteration(在每次迭代中使用相同的使用者)啟用與否,作用是一樣的。

如讀者對此有不同見解,歡迎與我聯絡,共同探討。目前,我十分費解。


延遲建立執行緒直到需要


當在JMeter中啟用延遲建立執行緒直到需要時,JMeter會根據預設的Ramp-up時間動態地分配執行緒。假設Ramp-up時間設定為20秒,執行緒數為10,那麼JMeter會在測試啟動後立即建立第一個執行緒並開始請求處理。隨後,每隔2秒,JMeter將建立下一個執行緒,直到所有執行緒都被啟動。

如果關閉“延遲建立執行緒直到需要”選項,JMeter會在測試開始時一次性建立所有執行緒。使用同樣的引數,即在測試一開始,JMeter會立即建立全部的10個執行緒。這些執行緒會按照設定的“Ramp-up時間”進行執行,每個執行緒將間隔2秒啟動。

延遲建立執行緒直到需要這一配置的目的是為了應對測試機效能有限的情況。透過這種方式,可以避免在測試初期就建立所有執行緒,導致資源過度佔用和可能的效能問題。這種方法有助於平滑地增加系統負載,同時防止資源瞬間緊張導致測試無法正常進行。


排程器-啟動延遲


排程器主要控制執行緒操作時間。啟用排程器後,可以輸入持續時間(值不能為空),啟動延遲來控制執行緒組的操作時間及執行緒組操作前的延遲時間。

同時輸入持續時間啟動延遲時,先計算啟動延遲,再計算持續時間

示例介面程式碼

@ThreadGroup.route('/api/ThreadGroup5/', methods=['GET', 'POST'])  
def threadgroup5():  
    return '200'

示例Jmeter指令碼

  • 測試計劃下新增執行緒組

    啟用排程器

    持續時間:10

    啟動延遲3

  • 執行緒組下新增1個HTTP 請求取樣器

    請求地址:HTTP://127.0.0.1:5000/api/ThreadGroup5/

    請求方式:GET

  • 測試計劃中,新增檢視結果樹

image

執行結果

image

注意看圖中右上角-黃色三角形左邊的計時器,值固定在2秒。這個計時器計算整個測試計劃的持續時間。由於示例請求的介面響應較快,可以理解為計時器的時間就是HTTP請求時的時間。

因為啟動延遲設定為3秒,所以HTTP請求會在延遲3秒執行。不過計時器的時間是2秒,誤差1秒。我多次試過把持續時間啟動延遲的時間拉長,誤差還是1秒。


排程器-持續時間


排程器主要控制執行緒操作時間。啟用排程器後,可以輸入持續時間(值不能為空),啟動延遲來控制執行緒組的操作時間及執行緒組操作前的延遲時間。

同時輸入持續時間啟動延遲時,先計算啟動延遲,再計算持續時間

示例介面程式碼

@ThreadGroup.route('/api/ThreadGroup6/', methods=['GET', 'POST'])  
def threadgroup6():  
    sleep(3)  
    return '200'

示例Jmeter指令碼

  • 測試計劃下新增執行緒組

    啟用排程器

    持續時間:2

  • 執行緒組下新增1個HTTP 請求取樣器

    請求地址:HTTP://127.0.0.1:5000/api/ThreadGroup6/

    請求方式:GET

  • HTTP 請求下新增1個固定定時器

    值:3000

  • 測試計劃中,新增檢視結果樹

image

執行結果

image

圖中結果樹中什麼都沒有,這是因為執行緒組的持續時間只有2秒,但固定定時器的延遲有3秒,導致還未執行取樣器,持續時間已經結束。

此時刪掉固定定時器,執行結果

image

此時有人會有疑問。介面中設定的休眠時間就已經是3秒了,指令碼中的持續時間還只是2秒,為什麼這次成功執行了呢?

持續時間的設定,只作用於還未執行的取樣器。已經執行的取樣器,無論等待多長時間,都會執行完成。


本文示例介面原始碼可從前言中下載。


相關文章