安装
C:\Users\lifeng01>pip install locust
Collecting locust
Downloading locust-2.5.0-py3-none-any.whl (795 kB)
|████████████████████████████████| 795 kB 364 kB/s
Requirement already satisfied: msgpack>=0.6.2 in d:\python\python37\lib\site-packages (from locust) (1.0.2)
Requirement already satisfied: ConfigArgParse>=1.0 in d:\python\python37\lib\site-packages (from locust) (1.4)
Collecting geventhttpclient>=1.5.1
Downloading geventhttpclient-1.5.3-cp37-cp37m-win_amd64.whl (36 kB)
Requirement already satisfied: requests>=2.9.1 in d:\python\python37\lib\site-packages (from locust) (2.25.0)
Collecting pyzmq>=22.2.1
Downloading pyzmq-22.3.0-cp37-cp37m-win_amd64.whl (1.1 MB)
|████████████████████████████████| 1.1 MB 252 kB/s
Collecting Flask-Cors>=3.0.10
Downloading Flask_Cors-3.0.10-py2.py3-none-any.whl (14 kB)
Requirement already satisfied: psutil>=5.6.7 in d:\python\python37\lib\site-packages (from locust) (5.8.0)
Requirement already satisfied: typing-extensions>=3.7.4.3 in d:\python\python37\lib\site-packages (from locust) (3.7.4.3)
Collecting Werkzeug>=2.0.0
Downloading Werkzeug-2.0.2-py3-none-any.whl (288 kB)
|████████████████████████████████| 288 kB 192 kB/s
Requirement already satisfied: Flask-BasicAuth>=0.2.0 in d:\python\python37\lib\site-packages (from locust) (0.2.0)
Requirement already satisfied: pywin32 in d:\python\python37\lib\site-packages (from locust) (228)
Collecting flask>=2.0.0
Downloading Flask-2.0.2-py3-none-any.whl (95 kB)
|████████████████████████████████| 95 kB 270 kB/s
Collecting roundrobin>=0.0.2
Downloading roundrobin-0.0.2.tar.gz (2.4 kB)
Preparing metadata (setup.py) ... done
Requirement already satisfied: gevent>=20.9.0 in d:\python\python37\lib\site-packages (from locust) (21.1.2)
Collecting Jinja2>=3.0
Downloading Jinja2-3.0.3-py3-none-any.whl (133 kB)
|████████████████████████████████| 133 kB 252 kB/s
Requirement already satisfied: click>=7.1.2 in d:\python\python37\lib\site-packages (from flask>=2.0.0->locust) (7.1.2)
Collecting itsdangerous>=2.0
Using cached itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Requirement already satisfied: Six in d:\python\python37\lib\site-packages (from Flask-Cors>=3.0.10->locust) (1.12.0)
Requirement already satisfied: zope.interface in d:\python\python37\lib\site-packages (from gevent>=20.9.0->locust) (5.3.0)
Requirement already satisfied: zope.event in d:\python\python37\lib\site-packages (from gevent>=20.9.0->locust) (4.5.0)
Requirement already satisfied: setuptools in d:\python\python37\lib\site-packages (from gevent>=20.9.0->locust) (41.2.0)
Requirement already satisfied: cffi>=1.12.2 in d:\python\python37\lib\site-packages (from gevent>=20.9.0->locust) (1.14.5)
Requirement already satisfied: greenlet<2.0,>=0.4.17 in d:\python\python37\lib\site-packages (from gevent>=20.9.0->locust) (1.0.0)
Requirement already satisfied: certifi in d:\python\python37\lib\site-packages (from geventhttpclient>=1.5.1->locust) (2020.4.5.1)
Requirement already satisfied: brotli in d:\python\python37\lib\site-packages (from geventhttpclient>=1.5.1->locust) (1.0.9)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in d:\python\python37\lib\site-packages (from requests>=2.9.1->locust) (1.26.2)
Requirement already satisfied: idna<3,>=2.5 in d:\python\python37\lib\site-packages (from requests>=2.9.1->locust) (2.9)
Requirement already satisfied: chardet<4,>=3.0.2 in d:\python\python37\lib\site-packages (from requests>=2.9.1->locust) (3.0.4)
Requirement already satisfied: pycparser in d:\python\python37\lib\site-packages (from cffi>=1.12.2->gevent>=20.9.0->locust) (2.20)
Collecting MarkupSafe>=2.0
Using cached MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl (14 kB)
Using legacy 'setup.py install' for roundrobin, since package 'wheel' is not installed.
Installing collected packages: MarkupSafe, Werkzeug, Jinja2, itsdangerous, flask, roundrobin, pyzmq, geventhttpclient, Flask-Cors, locust
Attempting uninstall: MarkupSafe
Found existing installation: MarkupSafe 1.1.1
Uninstalling MarkupSafe-1.1.1:
Successfully uninstalled MarkupSafe-1.1.1
Attempting uninstall: Werkzeug
Found existing installation: Werkzeug 1.0.1
Uninstalling Werkzeug-1.0.1:
Successfully uninstalled Werkzeug-1.0.1
Attempting uninstall: Jinja2
Found existing installation: Jinja2 2.11.2
Uninstalling Jinja2-2.11.2:
Successfully uninstalled Jinja2-2.11.2
Attempting uninstall: itsdangerous
Found existing installation: itsdangerous 1.1.0
Uninstalling itsdangerous-1.1.0:
Successfully uninstalled itsdangerous-1.1.0
Attempting uninstall: flask
Found existing installation: Flask 1.1.2
Uninstalling Flask-1.1.2:
Successfully uninstalled Flask-1.1.2
Running setup.py install for roundrobin ... done
Attempting uninstall: pyzmq
Found existing installation: pyzmq 22.0.3
Uninstalling pyzmq-22.0.3:
Successfully uninstalled pyzmq-22.0.3
Attempting uninstall: geventhttpclient
Found existing installation: geventhttpclient 1.4.4
Uninstalling geventhttpclient-1.4.4:
Successfully uninstalled geventhttpclient-1.4.4
Successfully installed Flask-Cors-3.0.10 Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.2 flask-2.0.2 geventhttpclient-1.5.3 itsdangerous-2.0.1 locust-2.5.0 pyzmq-22.3.0 roundrobin-0.0.2
准备入门
蝗虫(locust
)测试本质上是一个Python程序。这使得它非常灵活,尤其擅长实现复杂的用户流。但它也可以做简单的测试,所以让我们从这开始:
# -*-coding:utf-8 -*-
# ** createDate: 2021/11/19 10:31
# ** scriptFile: locustfiles.py
# ** __author__: Li Feng
"""
注释信息:
"""
from locust import HttpUser, task
class HelloWorldUser(HttpUser):
@task
def hello_world(self):
self.client.get("/hello")
self.client.get("/world")
这个用户将一次又一次地向/hello
和/world
发出HTTP
请求。将代码放入当前目录下名为locustfile.py的文件中,并运行locust
:
PS F:\project_gitee\Test\locustProject> locust -f locustfiles.py -H https://www.baidu.com
[2021-11-19 10:42:51,524] jszx-zlb/INFO/locust.main: Starting web interface at http://0.0.0.0:8089 (accepting connections from all network interfaces)
[2021-11-19 10:42:51,538] jszx-zlb/INFO/locust.main: Starting Locust 2.5.0
一旦您启动了蝗虫(locust
),打开一个浏览器并指向http://localhost:8089。界面显示如下:
名词解释:
- Number of users to simulate:设置模拟的用户总数
- Spawn rate (users spawned/second):每秒启动的虚拟用户数
- Host:待测域名
- Start swarming:开始执行
locust
脚本按钮
注意点,如果您命令行没有输入-H
加域名的话,web页面的的Host
栏就是空的,就得需要你手动输入了。
以上是web页面操作,你也可以直接使用命令行的无头操作:
PS F:\project_gitee\Test\locustProject> locust --headless --users 10 --spawn-rate 0.5 -f locustfiles.py -H https://www.baidu.com
[2021-11-19 11:28:46,379] jszx-zlb-047/INFO/locust.main: No run time limit set, use CTRL+C to interrupt
[2021-11-19 11:28:46,380] jszx-zlb-047/INFO/locust.main: Starting Locust 2.5.0
Name # reqs # fails | Avg Min Max Median | req/s failures/s
----------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregated 0 0(0.00%) | 0 0 0 0 | 0.00 0.00
[2021-11-19 11:28:46,383] jszx-zlb-047/INFO/locust.runners: Ramping to 10 users at a rate of 0.50 per second
(......)
忽略了一些显示报告
(......)
[2021-11-19 11:29:19,597] jszx-zlb/INFO/locust.main: Running teardowns...
[2021-11-19 11:29:19,597] jszx-zlb/INFO/locust.main: Shutting down (exit code 1), bye.
[2021-11-19 11:29:19,597] jszx-zlb/INFO/locust.main: Cleaning up runner...
Name # reqs # fails | Avg Min Max Median | req/s failures/s
----------------------------------------------------------------------------------------------------------------------------------------------------------------
GET /hello 6662 6662(100.00%) | 17 9 118 16 | 200.57 200.57
GET /world 6657 6657(100.00%) | 17 9 236 16 | 200.42 200.42
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregated 13319 13319(100.00%) | 17 9 236 16 | 401.00 401.00
Response time percentiles (approximated)
Type Name 50% 66% 75% 80% 90% 95% 98% 99% 99.9% 99.99% 100% # reqs
--------|--------------------------------------------------------------------------------|---------|------|------|------|------|------|------|------|------|------|------|------|
GET /hello 16 17 18 18 24 30 41 75 100 120 120 6662
GET /world 16 17 18 19 24 30 42 77 100 240 240 6657
--------|--------------------------------------------------------------------------------|---------|------|------|------|------|------|------|------|------|------|------|------|
None Aggregated 16 17 18 19 24 30 41 76 100 120 240 13319
Error report
# occurrences Error
----------------------------------------------------------------------------------------------------------------------------------------------------------------
93 GET /hello: RemoteDisconnected('Remote end closed connection without response')
6572 GET /world: HTTPError('404 Client Error: Not Found for url: https://www.baidu.com/world')
6569 GET /hello: HTTPError('404 Client Error: Not Found for url: https://www.baidu.com/hello')
84 GET /world: RemoteDisconnected('Remote end closed connection without response')
1 GET /world: ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None)
----------------------------------------------------------------------------------------------------------------------------------------------------------------
locustfiles.py文件的编写
首先我们看下官方提供的示例:
import time
from locust import HttpUser, task, between
class QuickstartUser(HttpUser):
wait_time = between(1, 5)
@task
def hello_world(self):
self.client.get("/hello")
self.client.get("/world")
@task(3)
def view_items(self):
for item_id in range(10):
self.client.get(f"/item?id={item_id}", name="/item")
time.sleep(1)
def on_start(self):
self.client.post("/login", json={"username":"foo", "password":"bar"})
引入的包:
- time:时间库
- HttpUser:是表示将生成一个
HTTP
用户,这个类会在实例化后保持请求之间的用户会话 - task:修饰符,声明任务(如果没有这个就不会对这个接口运行)
- between:返回一个函数,该函数返回一个介于min_wait和max_wait之间的随机数;还有一个是
constant
,它是设置固定的时间内
名词解释:
-
wait_time = between(1, 5)
:设置时间,最小为1,最大为5秒 -
@task(3)
:方法上装饰这个是声明这个是任务,3代表的是权重,默认权重是1 -
name="/item"
:是把该方法请求的10次,归类在item中 -
self.client.get
:是去请求接口,发送数据 -
on_start
:该方法是前置方法,优先运行的,通常放登录,登录会自动关联后续接口;还有一个后置是on_stop
方法
官方提供的例子,复制黏贴到.py文件中后,直接命令行运行即可,虽然是报错的,但是不影响观看,哈哈:
PS F:\project_gitee\Test\locustProject> locust -f locustfiles.py
-
-f
是指定文件
实践示例
以我们自己的项目为示例(代码中会有部分改动,主要是牵扯到一些隐私信息)进行负载测试:
import urllib3
from locust import HttpUser, TaskSet, task, between
class WebsiteLmsUser(TaskSet):
wait_time = between(1, 5)
def on_start(self):
urllib3.disable_warnings()
self.client.verify = False
self.client.headers.update({"Content-Type": "application/json"})
res = self.client.post("/api/auth", json={
"username": "account01",
"password": "123456",
"scenario": "web",
"day": 0
})
res_json = res.json()["data"]["token"]
self.client.headers.update({"token": res_json})
@task
def user_info(self):
self.client.get("/api/auth")
@task
def user_menu(self):
self.client.get("/api/auth/menu")
class WebsiteUser(HttpUser):
tasks = [WebsiteLmsUser]
host = "https://api-first.com"
min_wait = 1000
max_wait = 5000
名词解释:
-
on_start
中是写入了登录操作 -
WebsiteLmsUser
继承是TaskSet
类,该类是定义用户将执行的一组任务。 -
WebsiteUser
继承了HttpUser
类,该类是将生成一个HTTP用户
,并请求将要进行负载测试的系统 -
tasks = [WebsiteLmsUser]
这里是locust
用户将运行python可调用类或者TaskSet类的集合 -
host = "https://api-first.com"
指定了host,后面web页面就不需要输入了 -
min_wait和max_wait
是定义最长和最短等待时间
命令行输入命令开始运行:
PS F:\project_gitee\Test\locustProject> locust -f locustfiles.py
[2021-11-19 18:41:14,428] jszx-zlb/INFO/locust.main: Starting web interface at http://0.0.0.0:8089 (accepting connections from all network interfaces)
[2021-11-19 18:41:14,442] jszx-zlb/INFO/locust.main: Starting Locust 2.5.0
[2021-11-19 18:41:25,250] jszx-zlb/INFO/locust.runners: Ramping to 1 users at a rate of 1.00 per second
[2021-11-19 18:41:25,251] jszx-zlb/INFO/locust.runners: All users spawned: {"WebsiteUser": 1} (1 total users)
运行情况如下:
生成报告如下:
实际运行过程中,locust
一直执行的是负载测试,就是一直在持续运行,必须你自己手动停止,这样也能更好的检测系统接口性能的稳定性。此次只是基础的使用,这玩意还是很强大的,后续还有优化及分布等等。
以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,直接私信留言会及时修正发布;非常期待你的点赞和分享哟,谢谢!
未完,待续…
一直都在努力,希望您也是!
微信搜索公众号:就用python
作者:李 锋|编辑排版:梁莉莉