日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python 服务端性能_python 学习笔记---Locust 测试服务端性能

發布時間:2023/12/15 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 服务端性能_python 学习笔记---Locust 测试服务端性能 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

由于人工智能的熱度, python目前已經成為最受歡迎的編程語言,一度已經超越Java 。

本文將介紹開源的python 測試工具: locust

使用步驟:

1. 安裝python 3.0以上版本

2. 安裝Pip

3. 安裝locust? ? ?pip install locustio? (windows系統下)

4. 閱讀或者下載 locust 源碼

一、Locust 的基本實現原理

服務端性能測試工具最核心的部分是壓力發生器,核心要點有兩個,一是真實模擬用戶操作,二是模擬有效并發。

在Locust測試框架中,測試場景是采用純Python腳本。對于最常見的HTTP(S)協議的系統,Locust采用Python的requests庫作為客戶端,而對于其它協議類型的系統,Locust也提供了接口,只要我們能采用Python編寫對應的請求客戶端,就能方便地采用Locust實現壓力測試。從這個角度來說,Locust可以用于壓測任意類型的系統。

在模擬有效并發方面,Locust的優勢在于其摒棄了進程和線程,完全基于事件驅動,使用gevent提供的非阻塞IO和coroutine來實現網絡層的并發請求,因此即使是單臺壓力機也能產生數千并發請求數;再加上對分布式運行的支持,理論上來說,Locust能在使用較少壓力機的前提下支持極高并發數的測試。

二、 Locust 腳本編寫

首先分析下官方demo腳本:

importrandomfrom locust importHttpLocust, TaskSet, taskfrom pyquery importPyQueryclassBrowseDocumentation(TaskSet):defon_start(self):#assume all users arrive at the index page

self.index_page()

self.urls_on_current_page=self.toc_urls

@task(10)defindex_page(self):

r= self.client.get("/")

pq=PyQuery(r.content)

link_elements= pq(".toctree-wrapper a.internal")

self.toc_urls=[

l.attrib["href"] for l inlink_elements

]

@task(50)def load_page(self, url=None):

url=random.choice(self.toc_urls)

r=self.client.get(url)

pq=PyQuery(r.content)

link_elements= pq("a.internal")

self.urls_on_current_page=[

l.attrib["href"] for l inlink_elements

]

@task(30)defload_sub_page(self):

url=random.choice(self.urls_on_current_page)

r=self.client.get(url)classAwesomeUser(HttpLocust):

task_set=BrowseDocumentation

host= "http://docs.locust.io/en/latest/"

#we assume someone who is browsing the Locust docs,

#generally has a quite long waiting time (between

#20 and 600 seconds), since there's a bunch of text

#on each page

min_wait = 20 * 1000max_wait= 600 * 1000

在這個示例中,定義了針對host=http://docs.locust.io/en/latest/ 網站的測試場景:先模擬用戶登錄系統,然后隨機地訪問首頁(/)和關于頁面(/about/),請求比例為2:1;并且,在測試過程中,兩次請求的間隔時間為20~600秒間的隨機值。

那么,如上Python腳本是如何表達出以上測試場景的呢?

從腳本中可以看出,腳本主要包含兩個類,一個是WebsiteUser(繼承自HttpLocust,而HttpLocust繼承自Locust),另一個是WebsiteTasks(繼承自TaskSet)。事實上,在Locust的測試腳本中,所有業務測試場景都是在Locust和TaskSet兩個類的繼承子類中進行描述的。

Locust類

簡單地說,Locust類就好比是一群蝗蟲,而每一只蝗蟲就是一個類的實例。

相應的,TaskSet類就好比是蝗蟲的大腦,控制著蝗蟲的具體行為,即實際業務場景測試對應的任務集。

在Locust類中,具有一個client屬性,它對應著虛擬用戶作為客戶端所具備的請求能力,也就是我們常說的請求方法。

對于常見的HTTP(S)協議,Locust已經實現了HttpLocust類,其client屬性綁定了HttpSession類,而HttpSession又繼承自requests.Session。因此在測試HTTP(S)的Locust腳本中,我們可以通過client屬性來使用Python requests庫的所有方法,包括GET/POST/HEAD/PUT/DELETE/PATCH等,調用方式也與requests完全一致。另外,由于requests.Session的使用,因此client的方法調用之間就自動具有了狀態記憶的功能。常見的場景就是,在登錄系統后可以維持登錄狀態的Session,從而后續HTTP請求操作都能帶上登錄態。

而對于HTTP(S)以外的協議,我們同樣可以使用Locust進行測試,只是需要我們自行實現客戶端。在客戶端的具體實現上,可通過注冊事件的方式,在請求成功時觸發events.request_success,在請求失敗時觸發events.request_failure即可。然后創建一個繼承自Locust類的類,對其設置一個client屬性并與我們實現的客戶端進行綁定。后續,我們就可以像使用HttpLocust類一樣,測試其它協議類型的系統。

原理就是這樣簡單!

在Locust類中,除了client屬性,還有幾個屬性需要關注下:

task_set: 指向一個TaskSet類,TaskSet類定義了用戶的任務信息,該屬性為必填;

max_wait/min_wait: 每個用戶執行兩個任務間隔時間的上下限(毫秒),具體數值在上下限中隨機取值,若不指定則默認間隔時間固定為1秒;

host:被測系統的host,當在終端中啟動locust時沒有指定--host參數時才會用到;

weight:同時運行多個Locust類時會用到,用于控制不同類型任務的執行權重。

測試開始后,每個虛擬用戶(Locust實例)的運行邏輯都會遵循如下規律:

先執行WebsiteTasks中的on_start(只執行一次),作為初始化;

從WebsiteTasks中隨機挑選(如果定義了任務間的權重關系,那么就是按照權重關系隨機挑選)一個任務執行;

根據Locust類中min_wait和max_wait定義的間隔時間范圍(如果TaskSet類中也定義了min_wait或者max_wait,以TaskSet中的優先),在時間范圍中隨機取一個值,休眠等待;

重復2~3步驟,直至測試任務終止。

TaskSet類

性能測試工具要模擬用戶的業務操作,就需要通過腳本模擬用戶的行為。在前面的比喻中說到,TaskSet類好比蝗蟲的大腦,控制著蝗蟲的具體行為。

具體地,TaskSet類實現了虛擬用戶所執行任務的調度算法,包括規劃任務執行順序(schedule_task)、挑選下一個任務(execute_next_task)、執行任務(execute_task)、休眠等待(wait)、中斷控制(interrupt)等等。在此基礎上,我們就可以在TaskSet子類中采用非常簡潔的方式來描述虛擬用戶的業務測試場景,對虛擬用戶的所有行為(任務)進行組織和描述,并可以對不同任務的權重進行配置。

在TaskSet子類中定義任務信息時,可以采取兩種方式,@task裝飾器和tasks屬性。

采用@task裝飾器定義任務信息時,描述形式如下:

from locust importTaskSet, taskclassUserBehavior(TaskSet):

@task(1)deftest_job1(self):

self.client.get('/job1')

@task(2)deftest_job2(self):

self.client.get('/job2')

采用tasks屬性定義任務信息時,描述形式如下:

from locust importTaskSetdeftest_job1(obj):

obj.client.get('/job1')deftest_job2(obj):

obj.client.get('/job2')classUserBehavior(TaskSet):

tasks= {test_job1:1, test_job2:2}#tasks = [(test_job1,1), (test_job1,2)] # 兩種方式等價

Locust 用例高級用法

關聯

在某些請求中,需要攜帶之前從Server端返回的參數,因此在構造請求時需要先從之前的Response中提取出所需的參數。

from lxml importetreefrom locust importTaskSet, task, HttpLocustclassUserBehavior(TaskSet):

@staticmethoddefget_session(html):

tree=etree.HTML(html)return tree.xpath("//div[@class='btnbox']/input[@name='session']/@value")[0]

@task(10)deftest_login(self):

html= self.client.get('/login').text

username= 'user@compay.com'password= '123456'session=self.get_session(html)

payload={'username': username,'password': password,'session': session

}

self.client.post('/login', data=payload)classWebsiteUser(HttpLocust):

host= 'http://debugtalk.com'task_set=UserBehavior

min_wait= 1000max_wait= 3000

參數化

循環取數據,數據可重復使用

所有并發虛擬用戶共享同一份測試數據,各虛擬用戶在數據列表中循環取值。

例如,模擬3用戶并發請求網頁,總共有100個URL地址,每個虛擬用戶都會依次循環加載這100個URL地址;加載示例如下表所示。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

from locust importTaskSet, task, HttpLocustclassUserBehavior(TaskSet):defon_start(self):

self.index=0

@taskdeftest_visit(self):

url=self.locust.share_data[self.index]print('visit url: %s' %url)

self.index= (self.index + 1) %len(self.locust.share_data)

self.client.get(url)classWebsiteUser(HttpLocust):

host= 'http://debugtalk.com'task_set=UserBehavior

share_data= ['url1', 'url2', 'url3', 'url4', 'url5']

min_wait= 1000max_wait= 3000

保證并發測試數據唯一性,不循環取數據

所有并發虛擬用戶共享同一份測試數據,并且保證虛擬用戶使用的數據不重復。

例如,模擬3用戶并發注冊賬號,總共有9個賬號,要求注冊賬號不重復,注冊完畢后結束測試;加載示例如下表所示。

from locust importTaskSet, task, HttpLocustimportqueueclassUserBehavior(TaskSet):

@taskdeftest_register(self):try:

data=self.locust.user_data_queue.get()exceptqueue.Empty:print('account data run out, test ended.')

exit(0)print('register with user: {}, pwd: {}'\

.format(data['username'], data['password']))

payload={'username': data['username'],'password': data['password']

}

self.client.post('/register', data=payload)classWebsiteUser(HttpLocust):

host= 'http://debugtalk.com'task_set=UserBehavior

user_data_queue=queue.Queue()for index in range(100):

data={"username": "test%04d" %index,"password": "pwd%04d" %index,"email": "test%04d@debugtalk.test" %index,"phone": "186%08d" %index,

}

user_data_queue.put_nowait(data)

min_wait= 1000max_wait= 3000

保證并發測試數據唯一性,循環取數據

所有并發虛擬用戶共享同一份測試數據,保證并發虛擬用戶使用的數據不重復,并且數據可循環重復使用。

例如,模擬3用戶并發登錄賬號,總共有9個賬號,要求并發登錄賬號不相同,但數據可循環使用;加載示例如下表所示。

from locust importTaskSet, task, HttpLocustimportqueueclassUserBehavior(TaskSet):

@taskdeftest_register(self):try:

data=self.locust.user_data_queue.get()exceptqueue.Empty:print('account data run out, test ended.')

exit(0)print('register with user: {}, pwd: {}'\

.format(data['username'], data['password']))

payload={'username': data['username'],'password': data['password']

}

self.client.post('/register', data=payload)

self.locust.user_data_queue.put_nowait(data)classWebsiteUser(HttpLocust):

host= 'http://debugtalk.com'task_set=UserBehavior

user_data_queue=queue.Queue()for index in range(100):

data={"username": "test%04d" %index,"password": "pwd%04d" %index,"email": "test%04d@debugtalk.test" %index,"phone": "186%08d" %index,

}

user_data_queue.put_nowait(data)

min_wait= 1000max_wait= 3000

三、Locust運行模式

運行Locust時,通常會使用到兩種運行模式:單進程運行和多進程分布式運行。

單進程運行模式

Locust所有的虛擬并發用戶均運行在單個Python進程中,具體從使用形式上,又分為no_web和web兩種形式。該種模式由于單進程的原因,并不能完全發揮壓力機所有處理器的能力,因此主要用于調試腳本和小并發壓測的情況。

當并發壓力要求較高時,就需要用到Locust的多進程分布式運行模式。從字面意思上看,大家可能第一反應就是多臺壓力機同時運行,每臺壓力機分擔負載一部分的壓力生成。的確,Locust支持任意多臺壓力機(一主多從)的分布式運行模式,但這里說到的多進程分布式運行模式還有另外一種情況,就是在同一臺壓力機上開啟多個slave的情況。這是因為當前階段大多數計算機的CPU都是多處理器(multiple processor cores),單進程運行模式下只能用到一個處理器的能力,而通過在一臺壓力機上運行多個slave,就能調用多個處理器的能力了。比較好的做法是,如果一臺壓力機有N個處理器內核,那么就在這臺壓力機上啟動一個master,N個slave。當然,我們也可以啟動N的倍數個slave,但是根據我的試驗數據,效果跟N個差不多,因此只需要啟動N個slave即可。

Locust是通過在Terminal中執行命令進行啟動的,通用的參數有如下幾個:

-H, --host:被測系統的host,若在Terminal中不進行指定,就需要在Locust子類中通過host參數進行指定;

--no-web參數,指定并發數(-c)和總執行次數(-n)

-f, --locustfile:指定執行的Locust腳本文件;

在此基礎上,當我們想要調試Locust腳本時,就可以在腳本中需要調試的地方通過print打印日志,然后將并發數和總執行次數都指定為1

$ locust -f locustfile.py --no-web -c 1 -n 1

no_web

如果采用no_web形式,則需使用--no-web參數,并會用到如下幾個參數。

-c, --clients:指定并發用戶數;

-n, --num-request:指定總執行測試次數;

-r, --hatch-rate:指定并發加壓速率,默認值位1。

示例:

$ locust -H http://debugtalk.com -f demo.py --no-web -c 1 -n 2

web

如果采用web形式,,則通常情況下無需指定其它額外參數,Locust默認采用8089端口啟動web;如果要使用其它端口,就可以使用如下參數進行指定。

-P, --port:指定web端口,默認為8089.

$ locust -H http://XXXX.com -f demo.py

如果Locust運行在本機,在瀏覽器中訪問http://localhost:8089即可進入Locust的Web管理頁面;如果Locust運行在其它機器上,那么在瀏覽器中訪問http://locust_machine_ip:8089即可。

在Locust的Web管理頁面中,需要配置的參數只有兩個:

Number of users to simulate: 設置并發用戶數,對應中no_web模式的-c, --clients參數;

Hatch rate (users spawned/second): 啟動虛擬用戶的速率,對應著no_web模式的-r, --hatch-rate參數,默認為1。

多進程分布式運行

不管是單機多進程,還是多機負載模式,運行方式都是一樣的,都是先運行一個master,再啟動多個slave。

啟動master時,需要使用--master參數;同樣的,如果要使用8089以外的端口,還需要使用-P, --port參數。

$ locust -H http://xxxx.com -f demo.py --master --port=8088

master啟動后,還需要啟動slave才能執行測試任務。

啟動slave時需要使用--slave參數;在slave中,就不需要再指定端口了。

$ locust -H http://xxxx.com -f demo.py --slave

如果slave與master不在同一臺機器上,還需要通過--master-host參數再指定master的IP地址。

$ locust -H http://xxxx.com -f demo.py --slave --master-host=

master和slave都啟動完畢后,就可以在瀏覽器中通過http://locust_machine_ip:8089進入Locust的Web管理頁面了。使用方式跟單進程web形式完全相同,只是此時是通過多進程負載來生成并發壓力,在web管理界面中也能看到實際的slave數量。

注意:

locust雖然使用方便,但是加壓性能和響應時間上面還是有差距的,如果項目有非常大的并發加壓請求,可以選擇wrk

對比方法與結果:

可以準備兩臺服務器,服務器A作為施壓方,服務器B作為承壓方

服務器B上簡單的運行一個nginx服務就行了

服務器A上可以安裝一些常用的壓測工具,比如locust、ab、wrk

我當時測下來,施壓能力上 wrk > golang >> ab > locust

因為locust一個進程只使用一核CPU,所以用locust壓測時,必須使用主從分布式(zeromq通訊)模式,并根據服務器CPU核數來起slave節點數

wrk約為55K QPS

golang net/http 約 45K QPS

ab 大約 15K QPS

locust 最差,而且response time明顯比較長

總結

以上是生活随笔為你收集整理的python 服务端性能_python 学习笔记---Locust 测试服务端性能的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。