天天看點

好用的python性能測試神器–Locust

原文連結:https://mp.weixin.qq.com/s/9PxSPuHmucSLi_welq6uNQ

現在性能測試工具太多,根據業務不同使用,比如說我們熟悉的loadrunner、jmeter、ab、webbench等等,這些工具是也主流大部分也在使用,但是如果你能看懂python代碼,會寫就更好了,可以根據自已的業務編寫,不會自己寫架構也可以嘗試一下今天的主角Locust,一款基于python的開源性能測試工具,主要也是負載測試工具,它的優點是學習起來比較簡單,功能完全自定制,自由控制業務邏輯,使用比較靈活,支援分布式。

它主要就是模拟一群使用者将通路你的背景。每個使用者的行為由你編寫的python代碼定義,同時可以從Web界面中實時觀察到使用者的行為。

Locust完全是事件驅動的,是以在單台機器上能夠支援幾千并發使用者通路。

與其它許多基于事件的應用相比,Locust并不使用回調,而是使用gevent,而gevent是基于協程的,可以用同步的方式來編寫異步執行的代碼。每個使用者實際上運作在自己的greenlet中。

所有的性能測試工具都至少包含這3方面:

1、壓力産生器,也就是可以指定産生多大的壓力,多少并發;

   2、資料統計,也就是結果的展示,要統計TPS【QPS】是多少,響應時間多少等等,這些資料; 

   3、代理功能,代理功能簡單來說就4個字,分攤壓力:如說你壓測的時候要用1000個并發,但是你的電腦(壓力機)配置比較弱,隻支援500并發,再大電腦就死掉了,完犢子,壓測不了。那怎麼辦呢,就得分攤壓力,從其他伺服器發壓力,那就可以了,每台伺服器上500個并發,人多好幹活嘛,代理就是幹這個的,把這個上面的壓力分攤到别的電腦上。
           

當然今天的主角Locust這3個功能都是有的,locust的官網是 www.locust.io,有詳細的文檔檢視。

Locust其實是python的一個第三方子產品,安裝很簡單,直接pip install locust即可,或者自己下載下傳安裝包,手動安裝。安裝完成後,就有locust指令,在指令行裡面輸入 locust --help,有幫助資訊就安裝成功了。

如何用呢,很簡單,隻需要幾行代碼就可以實作,并且有漂亮的web界面也可用指令行執行,可以設定并發數,和檢視結果,當然缺點也是有的,就是沒有資源使用率統計,需自行在被測伺服器中監控。

先寫幾行簡單的代碼,寫一個打開BestTest首頁的腳本。

from locust import HttpLocust, TaskSet, task

HttpLocust 這個類的作用是用來發送http請求的

TaskSet 這個類是定義使用者行為的,相當于loadrunnerhttp協定的腳本,jmeter裡面的http請求一樣,要去幹嘛的

task 這個task是一個裝飾器,它用來把一個函數,裝飾成一個任務,也可以指定他們的先後執行順序

class BestTest(TaskSet):

自己定義的類,繼承TaskSet,也就是這個類是實作咱們要去請求什麼的

@task#用task裝飾器把這個函數裝飾成一個咱們要執行的性能任務

def index(self):#這個函數裡面定義的是咱們要具體做的操作

self.client.get(\'/\')#請求這個url裡面的哪個路徑,如果是接口的話,就是哪個接口

class BestTestIndexUser(HttpLocust):

這個類繼承了HttpLocust,代表每個并發裡面的每個使用者

task_set = BestTest #這個是每個使用者都去幹什麼,指定了BestTest這個類,它就會每個使用者去運作besttest這個類裡面的方法

if name == "main":

import os

os.system("locust -f ./load_test.py --host=https://mp.weixin.qq.com/s/rhjKkj7pKpLX0YtbKOZxew")

或者注釋掉程式入口代碼,直接指令行執行下面

locust -f besttest.py --host=https://mp.weixin.qq.com/s/rhjKkj7pKpLX0YtbKOZxew

-f是指定一個python檔案 後面跟上咱們剛才寫的python檔案

--host是你要通路哪個背景,後面跟的url

預設端口号8090,啟動locust:運作完之後,通路的時候用ip:8090就可以通路了.

好用的python性能測試神器–Locust

locust控制台頁面:

好用的python性能測試神器–Locust

開始測試後的頁面:

好用的python性能測試神器–Locust

tps圖和響應時間圖:

好用的python性能測試神器–Locust

剛才上面寫的例子是單個接口壓測, 或者更說單場景的,如果想做混合場景的壓測。

隻需要寫多個task就可以了,也就是在類裡面寫多個函數,想誰想執行,标上數字就行了,1,2,3,4代碼如下:

不同類型的模拟使用者

1.考慮一種測試場景:如果我們想測試前端使用者登入和詳情,需要并發100個人,并且使其中10個人登入,另外90個人在詳情頁瞎逛,用locust架構應該如何實作呢?架構的指令行有提示locust [options] [LocustClass [LocustClass2 ...]]

當我們使用架構運作一個測試腳本時,如果腳本中隻有一個Locust類,則架構會以這個類作為模拟使用者的模闆;如果該腳本中不止一個Locust類,則需要指定類名;如果需要模拟多種類型的使用者,則可以指定多個類名,架構會根據每個Locust類的權重配置設定模拟使用者的比例(預設權重為10)。

一個簡單示例如下:

from locust import TaskSet, HttpLocust, task, TaskSequence, seq_task, InterruptTaskSet

class LoginTaskSet(TaskSet):

@task

def login(self):

print("登入")

class DetailsTaskSet(TaskSet):

@task

def details(self):

print("詳情頁")

class UserOwn(HttpLocust):

weight = 10

task_set = LoginTaskSet

host = "https://mp.weixin.qq.com/s/rhjKkj7pKpLX0YtbKOZxew"

min_wait = 10000

max_wait = 10000

class UserTwo(HttpLocust):

weight = 90

task_set = DetailsTaskSet

host = "https://mp.weixin.qq.com/s/rhjKkj7pKpLX0YtbKOZxew"

min_wait = 10000

max_wait = 10000

指令行運作:locust -f ***.py UserOwn UserTwo

如果并發10人,就會有1人在登入,9人在詳情頁瞎逛了,業務是自己編的

2.TaskSet的tasks屬性

定義任務的方式,就是在TaskSet類中定義一個方法,并标注其為@task;另一個定義任務的方式就是使用TaskSet的tasks屬性,這個屬性值可以是數組或字典,其中表示的任務可以是一個函數,也可以是另一個TaskSet。如果使用數組,其元素可以是元組(callable, int),int值即為該任務的權重。

2.1函數

示例中的tasks = [(play_one, 5), play_two]與tasks = {play_one: 5, play_two: 1}是完全等價的。tasks中的函數和有注解@task的函數有同等的地位,都是這個TaskSet的一個基本機關。

函數需有一個參數表示self

def test_one(self):

print("test_one")

def test_two(self):

print("test_two")

class TestTaskSet(TaskSet):

tasks = [(test_one, 5), test_two]

@task

def test(self):

print("the test is me")

class TestTwo(HttpLocust):

weight = 90

task_set = TestTaskSet

host = "https://mp.weixin.qq.com/s/rhjKkj7pKpLX0YtbKOZxew"

min_wait = 100

max_wait = 100

2.2嵌套TaskSet

tasks屬性的元素也可以是另一個TaskSet,這種做法就會形成嵌套的子任務。例如:我們測試前端,需要每一個使用者在詳情頁瞎逛的時候,有1/10的機率進入詳情頁進行另外的操作,詳情頁逛完退回首頁繼續閑逛,示例如下:

class TestTaskSet(TaskSet):

tasks = [test_one, test_two]

@task(5)

def test_details(self):

print("the details is Wandering")

@task

def end_details(self):

print("details end")

self.interrupt()

class TestOutTaskSet(TaskSet):

tasks = {TestTaskSet: 1}

@task(9)

def Test_out(self):

print("the details is out")

當進入嵌套的任務集執行任務後,會根據嵌套任務集的任務權重執行任務,除非調用self.interrupt()或抛出中斷異常raise InterruptTaskSet否則将一直在子任務集中執行下去

3.内部類

還有一種實作嵌套子任務的方式是使用内部類,如上訴示例,等同于:

class TestOutTaskSet(TaskSet):

@task(9)

def Test_out(self):

print("the details is out")

@task

class TestTaskSet(TaskSet):

tasks = [test_one, test_two]

@task(5)
   def test_details(self):
       print("the details is Wandering")

   @task
   def end_details(self):
       print("details end")
       self.interrupt()
           

4.類的繼承

如果一個TaskSet的父類是另一個TaskSet,那麼父類的所有任務會同樣的成為子類的任務。

5.最後尾聲

Locust類是建立模拟使用者的模闆,是以如果我們要使用不同的角色進行測試時,就需要給架構提供不同的Locust類。TaskSet類是模拟需要執行的任務集,我覺得可以這麼了解,這是一個任務的池子,裡面的每個機關都是一個任務,這個任務可以是函數也可以是另一個TaskSet,這個任務的定義方式有幾個(目前TaskSet通過@task定義,繼承父類的任務,tasks屬性中一個元素),但它們都是同等地位的,執行的機率與它們的權重相同,每一次模拟使用者都會從這個池子裡挑選任務進行執行(直到stop_timeout或頁面點選Stop)。當挑選到一個類型為TaskSet的任務執行時,就進入了嵌套的子任務當中,相當于到了子任務的池子裡開始挑選任務執行(直到調用self.interrupt()或抛出中斷異常raise InterruptTaskSet)。