Locust-入門


背景:

目前網上的教程基本都是1.0之前的,locust叢1.0版本就發生了較多的變化,網上的教程基本不可用了。本文基於locust最新版本2.5.1,作為筆記也作為入門教程分享。

(備注:只講 框架的使用 ,不涉及性能測試理論知識)

一、什么是Locust

Locust 是一種易於使用、可直接使用pyhton編寫腳本運行且可擴展的性能測試工具。

 

二、特點

  • 直接使用python 編寫測試腳本    
  • 支持分布式和可擴展-支持數十萬並發用戶
  • 提供友好的web界面
  • 可以測試任何系統
  • 小且靈活

 

locust 的web 運行界面

locust 提供了友好的web界面用於監控性能測試過程中的相關數據 

啟動頁

 

 測試監控界面

 

type 請求類型  
Name 請求名稱 這個可以自定義,傳name參數即可
Requests 當前已完成的請求數量  
Fails 失敗的請求數量  
Requests 當前已完成的請求數量  
Median 響應時間的中間值,即50%的響應時間在這個數值范圍內,單位為毫秒  
90%ile 90%的響應時間在正態分布平均值下方,即小於這個值  
Min 最小響應時間,單位為毫秒  
Max 最大響應時間,單位為毫秒  
average Size 平均每個請求的數據量,單位為字節  
current RPS 每秒鍾處理請求的數量

 

 

 

RPS(TPS)

 

響應時間 

 

 

Users

 

測試任務統計

 

支持下載測試報告

 

 進程信息,這里啟動了5個進程,用戶數為500,被平均分給了5個進程,

 

三、編寫任務

名詞解釋:

  任務:簡單的理解就是,你想要你腳本的虛擬用戶去做哪些事,比如請求某一個接口,或者執行某一個事件。

  用戶:可以理解為,執這個任務的實例主體,或者在locust 中,也可以認為是一群蝗蟲

 

  舊版本使用的是TaskSet進行任務或者請求編寫,然后在使用HttpLocust進行任務或者請求聲明,以及基礎屬性配置,一般會進行思考時間、host、task_set設置任務類等;新版本將HttpLocust重寫成User,並且HttpUser繼承於User,所以推薦使用HttpUser進行任務聲明;另外TaskSet中的task_set已被刪除,如果仍要使用TaskSet,則需要在HttpUser中使用tasks進行存儲

 

TaskSet 類 進行任務編寫

TaskSet是定義用戶將執行的一組任務的類,然后通過虛擬用戶調用並執行這一組任務

單個任務集合:  

from locust import TaskSet, task,User
import os

''' 
通過TaskSet 編寫任務
'''
class Task_1(TaskSet):

    @task
    def task1(self):
        print('task1----------')

    @task
    def task2(self):
        print('task2----------')

    @task
    def task3(self):
        print('task3----------')

class task_conf(User):
    tasks = [Task_1]

if __name__ == '__main__':
    os.system('locust -f TaskSet定義用戶任務.py --web-host "127.0.0.1"')

多個任務集合

切記 不要忘記調用調用 self.interrupt() 以跳出當前任務集

from locust import TaskSet, task,User
import os

''' 
TaskSet類定義了每個用戶的任務集合,
注意:如果存在多個任務集合,需要在每個任務集合中調用interrupt()方法,
否則用戶一旦進入到這個用戶,則無法跳出這個任務集合(會一直執行這個任務集)
'''
class Task_1(TaskSet):

    @task
    def task1(self):
        print('task1----------')

    @task
    def task2(self):
        print('task2----------')

    @task
    def task3(self):
        print('task3----------')

    #調用interrupt() 非常重要,否則用戶將難以自拔
    @task
    def logout(self):
        self.interrupt()

class Task_2(TaskSet):

    @task
    def task21(self):
        print('task21----------')

    @task
    def task22(self):
        print('task22----------')

    @task
    def task23(self):
        print('task23----------')

    @task
    def logout(self):
        self.interrupt()


class task_conf(User):
    
    tasks = [Task_1,Task_2]

if __name__ == '__main__': os.system('locust -f TaskSet定義用戶任務_多個.py --web-host "127.0.0.1"')

 

User類 編寫任務 

User 執行測試任務的主體類,用戶的行為由其任務定義

from locust import TaskSet, task,User
import os

''' 
通過TaskSet 定義任務
'''
class Task_1(User):

    @task
    def task1(self):
        print('task1----------')

    @task
    def task2(self):
        print('task2----------')

    @task
    def task3(self):
        print('task3----------')

if __name__ == '__main__':
    os.system('locust -f User定義用戶任務.py --web-host "127.0.0.1"')

 

任務屬性

測試開始時,locust將為每一個模擬用戶創建一個User類的實例,每個實例都在他們自己的微線程中執行,當這些用戶運行時,開始選中要執行的任務,休眠一段時間,然后選一個新的任務,繼續執行,以此類推。

這里我們為用戶添加任務的方式有兩種

  • 使用@task 裝飾器
  • 設置tasks屬性

@task

通過@task 定義用戶任務 任務 ,同時還可以通過@task(int) 設置每個任務的權重
from locust import task,User
import os # 通過@task 定義用戶任務 任務 ,同時還可以通過@task(int) 設置每個任務的權重 class task_2(User): @task(2) def task1(self): print('執行任務1') @task(2) def task2(self): print('執行任務2') @task(1) def task3(self): print('執行任務3') if __name__ == '__main__': os.system('locust -f task裝飾器聲明任務.py --web-host="127.0.0.1"')

 

tasks 

tasks屬性可以是一個 Task 列表,也可以是一個 {'Task':int} 的dict, Task可以是 一個測試方法或者函數,也可以是任務集合TakSet類

以User類為例

from locust import User
import os ''' 繼承TaskSet,不按順序執行任務, ''' # 通過tasks 定義測試任務 class task_1(User): def task1(self): print('執行任務1') def task2(self): print('執行任務2') def task3(self): print('執行任務3') # 通過tasks 定義測試任務 並設置對應任務執行權重 tasks = [task1, task2, task3] # tasks = {task1:1,task2:2,task3:2} if __name__ == '__main__': os.system('locust -f tasks屬性聲明用戶任務.py --web-host="127.0.0.1"')

 

任務標記@tag

可以通過標記的方式,執行負載測試時,讓虛擬用戶只執行指定的測試任務

from locust import User,tag

'''
設置tag,用於設置用戶 執行指定標記的任務
'''
class myUser(User): @tag('回歸') def task_1(self): print('回歸任務') @tag('預發') def task_2(self): print('任務2') @tag('回歸','預發') def task_3(self): print('回歸任務+預發任務') tasks = [task_1,task_2,task_3] if __name__ == '__main__': import os os.system('locust -f locust_user_tag.py --tags 回歸 --web-host="127.0.0.1"')

 

 User類的一些通用屬性

Locust 將為每個用戶生成一個 User 類的實例。用戶類可以定義一些通用屬性。

wait_time 屬性:

用於模擬用戶每次執行任務后的延遲時間(等同思考時間),如果未指定,則下一個任務將在完成后立即執行。

  • constant(x)  固定時間
  • between(x,y)     最小值和最大值之間的隨機時間
  • constant_packing(x)  每x秒 最多運行一次任務
  • constant_throughtput(x)     每秒最多運行x次
constant
from locust import constant, task,User
import os

''' 
wait_time = constant() 等待一個固定的時間
'''
class Task_1(User):

    @task
    def task1(self):
        print('task1----------')

    @task
    def task2(self):
        print('task2----------')

    @task
    def task3(self):
        print('task3----------')

    # 用戶執行每個任務,會固定等待5s
    wait_time = constant(5)

if __name__ == '__main__':
    os.system('locust -f task_wait_constant.py --web-host "127.0.0.1"')
between
from locust import between, task, User
import os

''' 
wait_time = between() 等待一個最小值和最大值之間的隨機時間 不含最大時間
'''

class Task_1(User):

    @task
    def task1(self):
        print('task1----------')

    @task
    def task2(self):
        print('task2----------')

    @task
    def task3(self):
        print('task3----------')

    # 用戶執行每個任務,會固定等待[1,5) 秒
    wait_time = between(1,5)


if __name__ == '__main__':
    os.system('locust -f task_wait_between.py --web-host "127.0.0.1"')

 

weight權重屬性

用於設置特定類型的用戶的 權重值,在未設置的情況下,locust將為每個用戶類生產相同數量的用戶實例

比如app用戶是web用戶的3倍

from locust import User

# app用戶數量是web用戶數量的3倍
class appUser(User):
    weight = 3
 
    def task_1(self):
        print('app任務1')

    def task_2(self):
        print('app任務2')

    tasks = [task_1,task_2]

class webUser(User):
    weight = 1

    def task_A(self):
        print('web任務1')

    def task_B(self):
        print('web任務2')

    tasks = [task_A, task_B]

if __name__ == '__main__':
    import os
    os.system('locust -f locust_user_weight.py --web-host="127.0.0.1"')

 

 host 主機屬性:

用於加載主機的url 前綴,(比如:http://baidu.com)

也可以在 webui中指定,或者命令參數中指定--host

from locust import task,HttpUser
import os

'''
主機屬性 host 
'''

class task_s(HttpUser):

    host = 'http://wthrcdn.etouch.cn'
    @task
    def task_1(self):
        url = '/weather_mini?city=杭州'
        # body = {'city':'杭州'}
        res = self.client.request(method='get',url=url)
        print(res.json())

if __name__ == '__main__':
    os.system('locust -f locust_host.py --web-host="127.0.0.1"')

 

前后置方法 on_start和on_stop方法

用戶將 on_start在它開始運行時調用它的方法

on_stop在它停止運行時調用它的方法。

from locust import User,constant

'''
   每個虛擬用戶 執行前
   會執行一次該方法(在一次測試結束后,只會執行一次)
'''

class myuser(User):
    wait_time = constant(2)
   
    def on_start(self):
        print('登錄')
    def on_stop(self):
        print('登出')

    def task_1(self):
        print('任務1')


    tasks = [task_1]

if __name__ == '__main__':
    import os
    os.system('locust -f locust_start_stop.py --web-host="127.0.0.1"')

 

 

HttpUser類

HttpUser是最常用的 User ,它通過client 發送Http請求,client是httpsession的一個實例(requests模塊的session),故在locust中,通過client 發送的請求,具有天然的保持會話能力。

發送http請求

from locust import HttpUser,task
import os class TaskA(HttpUser):
#登錄 def on_start(self): url = 'https://www.processon.com/login/quick_login' data = {'type': 'account_login', 'login_email': 12345678901, 'login_password': '123456', } r = self.client.request('post', url=url, data=data) #登錄成功調用個人信息接口 @task def test_login(self): url = 'https://www.processon.com/setting/account' r = self.client.request('post', url=url) print(r.text) if __name__ == '__main__': os.system('locust -f http_通過session請求.py --web-host="127.0.0.1"')

 

響應檢查

HttpUser 支持設置響應檢查點

使用catch_response參數、with語句和對response.failure()  標記為失敗

from locust import HttpUser, task
import os from json import JSONDecodeError import jsonpath class task_s(HttpUser): @task def task_1(self): get_url = 'http://wthrcdn.etouch.cn/weather_mini?city=杭州' with self.client.request(method='get', url=get_url,catch_response=True) as response: try: # 獲取響應內容的status 字段值 status = response.json()['status'] # 獲取響應時間 # rt = response.elapsed.total_seconds() # print(rt) # 如果status為1000則為成功,否則為失敗 if status == 1000: response.success() # if rt <= 0.001: # response.success() # else: # response.failure('響應超時') else: response.failure('非法的參數') except JSONDecodeError: response.failure('Response could not be decoded as JSON') if __name__ == '__main__': os.system('locust -f locust_HttpUse_檢查響應.py --web-host="127.0.0.1"')

 

FastHttpUser (locust大殺器)

Locust 的默認 HTTP 客戶端使用python-requests,而requests庫是一個同步阻塞庫(每個請求發送完成之后都在等待響應的回來,這在高並發場景下是致命的)

正因為如此,Locust 還附帶FastHttpUser使用geventhttpclient代替。它提供了一個非常相似的 API,並且使用的 CPU 時間顯着減少,通常情況下將給定硬件上每秒的最大請求數增加了 5 到 6 倍。

官方文檔FastHttpUser 和 HttpUser 比較
使用 FastHttpUsers 的測試將能夠在每個核心每秒執行接近 5000 個請求, 使用 HttpUser 大約 850 個

使用上:只需繼承 FastHttpUser 就可以了,其他和 HttpUser 沒有什么太大的差別

from locust import task,FastHttpUser
import os
import logging as log

class task_s(FastHttpUser):
    host = 'http://wthrcdn.etouch.cn'
    @task
    def task_1(self):
        get_url = '/weather_mini?city=杭州'
        self.client.request(method='get', path=get_url)
        # with self.client.request(method='get', path=get_url,catch_response=True) as response:
        #     status = response.json()['status']
        #     if status ==1000:
        #         response.success()
        #
        #     else:
        #         response.failure('請求失敗')


if __name__ == '__main__':
    os.system('start locust -f 通過FastHttpUser多進程發送請求.py  --master --web-host="127.0.0.1"')
    for i in range(8):
            os.system('start locust -f 通過FastHttpUser多進程發送請求.py  --worker')

並發數1500,tps在9000左右

 

 對比jmeter,並發數1500, tps在 8000左右

 

 

四、運行方式

命令參數運行

#進入當前模塊文件目錄,直接輸入
locust

#非當前文件目錄
locust -f  xx/xx.py 

#指定host
locust -f  xx/xx.py  --host=https://www.cnblogs.com

#指定locust webui 界面地址,
locust -f  xx/xx.py  --web-host ="127.0.0.1"

#不帶ui界面運行,
locust -f  xx/xx.py  --headless -u 1000 -r 100 --run-time 5m
--headless 沒有webui的情況下運行
-u  要生成的用戶數
-r   每秒啟動的用戶數
--run-time 5m 設置測試執行時間 這里是5分鍾,時間到了就會停止運行

#多進程運行 主模式啟動 8089端口用於web界面 ,5557用於從機交互 locust -f xx/xx.py --master 啟動一個進行執行 locust -f xx/xx.py --worker --master-host=192.168.0.14 (如果單機器運行,則可以省略后面的參數 --master-host=xxx.xxx.xxx.xxx)

 配置文件方式運行

locust 支持配置文件方式運行

(本質上也是命令行運行,只不過是把命令參數寫在了配置文件中,防止每次輸的時候 寫錯)

默認情況下,locust在~./.locust.conf 和 ./locust.conf ,還可以使用 --config 來指定配置文件運行

# -*- coding: UTF-8 -*
'''
# locust 默認讀取配置文件的優先級順序(覆蓋讀取)
# ~/locust.conf -> ./locust.conf ->(file specified using --conf)
# 注意:如果同時存在 兩個配置文件,locust.conf 和 diy.conf
# 此時使用 locust --config = diy.conf 讀取的將還是locust.conf
'''

# 要運行的py文件
locustfile = ./my_locust_file.py
# 設置是否帶webui運行
headless = false
# 設置weiui的地址
web-host= 127.0.0.1
# 設置 host
host = http://wthrcdn.etouch.cn
# 設置虛擬用戶數
users = 500
# 設置每秒增加的用戶數
spawn-rate = 10
# 設置運行時間,滿足設置的運行時間后,將停止運行
run-time = 1m

 

 

 

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM