文章略长
Locust学习笔记汇总
html
如有错误,请指正python
内容以官网为准
https://locust.io/git
Locust简介 Locust是什么?
Locust
是一个简单易用的分布式用户负载测试工具。它用于web站点(或其余系统)的负载测试,并计算一个系统能够处理多少并发用户。github
在测试中,一群locusts(蝗虫)会攻击你的网站。每一个locusts (或者测试用户)的行为由您定义,集群过程由web UI实时监控。这将帮助你在容许实际用户使用以前测试并肯定代码中的瓶颈。web
Locust
彻底基于事件,所以能够在一台计算机上支持数千个并发用户。与许多其余基于事件的应用程序不一样,它不使用回调。相反,它经过gevent使用轻量级进程。每一个汇集站点上的蝗虫其实是在它本身的进程中运行的(正确的说是greenlet)。这容许你使用Python编写很是有表现力的场景,而不用回调使代码复杂化。docker
Locust功能特性
用普通的Python编写用户测试场景
不须要笨拙的UI或庞大的XML,只需像一般那样编码便可。基于协程而不是回调,您的代码看起来和行为都与正常的、阻塞Python代码同样。shell分布式和可扩展——支持成千上万的用户
Locust支持在多台机器上运行负载测试。因为基于事件,即便一个Locust节点也能够在一个进程中处理数千个用户。这背后的部分缘由是,即便你模拟了那么多用户,也不是全部用户都积极的访问你的系统。一般,用户无所事事,想知道下一步该怎么作。每秒请求数不等于在线用户数。数据库基于web的UI
Locust具备简洁的HTML + JS用户界面,可实时显示相关的测试细节。并且因为UI是基于Web的,所以它是跨平台且易于扩展的。json能够测试任何系统
尽管Locust是面向web的,但它几乎能够用于测试任何系统。只须要未测试的内容编写一个客户端,而后用Locust访问!超级简单!windows可控
Locust很小,很容易被入侵,咱们打算保持这种状态。事件I / O和协程的全部繁重工做都委托给gevent。替代测试工具的脆弱性是咱们建立Locust的缘由。
Locust背景
Locust
的诞生是由于咱们厌倦了现有的解决方案。对我来讲,他们都没有解决正确的问题,没有抓住重点。咱们已经尝试了Apache JMeter和Tsung。
这两种工具均可以使用;咱们已经在工做中屡次使用了前一种方法。JMeter附带UI界面,您可能会认为这是一件好事。可是您很快就会意识到,经过某些点击界面“编码”你的测试方案是一种陷阱。其次,JMeter是线程绑定的。这意味着对于要模拟的每一个用户,都须要一个单独的线程。不用说,在一台机器上对成千上万的用户进行基准测试是不可行的。
另外一方面,Tsung没有这些线程问题,由于它是用Erlang编写的。它能够利用BEAM自身提供的轻量级流程,而且能够愉快地扩展规模。可是在定义测试场景时,Tsung和JMeter同样有限。它提供了基于XML的DSL来定义用户在测试时的行为方式。我想您能够想象“编码”这一点的恐怖。完成后显示各类图形或报告,须要对测试生成的日志文件进行后期处理。只有这样,您才能了解测试的具体状况。
无论怎样,咱们在创造Locust
的时候已经尝试解决这些问题。但愿以上这些痛点都不存在。
我猜你可能会说咱们真的只是在这里挠痒痒。咱们但愿其余人会发现它和咱们同样有用。
安装
Locust能够在PyPI上使用,而且能够与pip一块儿安装。
1$ pip3 install locust
若是您想要最新版本,可使用pip直接从咱们的Git存储库安装。例如,要使用Python 3安装master分支:
1pip3 install -e git://github.com/locustio/locust.git@master#egg=locustio
安装了Locust以后,您的shell中应该可使用Locust命令。(若是您没有使用virtualenv—您应该使用—请确保您的python脚本目录位于您的路径上)。
要查看可用的选项,请运行:
1$ locust --help
Python版本支持
在Python 3.六、3.7和3.8
Windows上安装locust
在Windows上,运行pip install locustio
便可。
可是,若是没有成功,那么能够先安装为pyzmq、gevent和greenlet预先构建的二进制包来修复它。
你能够在这里找到一个非官方的集合,预先创建的python包的windows:
http://www.lfd.uci.edu/~gohlke/pythonlibs/
下载预构建的.whl
文件后,可使用如下方法进行安装:
1$ pip install name-of-file.whl
而后可使用pip install locustio
进行安装。
注意:
在Windows上运行Locust应该能够很好地开发和测试您的负载测试脚本。可是,在运行大规模测试时,建议您在Linux机器上这样作,由于gevent在Windows下的性能不好。
macOS上安装Locust
当前是使用Homebrew在OS X上安装gevent的最短路径。
安装Homebrew。
安装libev(gevent的依赖):
1brew install libev
增长打开文件最大数限制
机器上的每一个HTTP链接打开一个新文件(技术上称为文件描述符)。操做系统能够为可打开的文件的最大数量设置一个较低的限制。若是该限制小于测试中模拟用户的数量,则会发生故障。
将操做系统的默认最大文件数限制增长到大于你要运行的模拟用户数的数量。如何执行此操做取决于所使用的操做系统。
快速入门Locust
例子locustfile.py
下面是一个简单的locustfile.py的小例子:
1from locust import HttpLocust, TaskSet, between
2
3def login(l):
4 l.client.post("/login", {"username":"ellen_key", "password":"education"})
5
6def logout(l):
7 l.client.post("/logout", {"username":"ellen_key", "password":"education"})
8
9def index(l):
10 l.client.get("/")
11
12def profile(l):
13 l.client.get("/profile")
14
15class UserBehavior(TaskSet):
16 tasks = {index: 2, profile: 1}
17
18 def on_start(self):
19 login(self)
20
21 def on_stop(self):
22 logout(self)
23
24class WebsiteUser(HttpLocust):
25 task_set = UserBehavior
26 wait_time = between(5.0, 9.0)
这里咱们定义了一些Locust任务,它们是普通的Python可调用函数,带有一个参数(一个Locust
类实例)。这些任务收集在tasks属性中的TaskSet
类下。而后,咱们有一个表明用户的HttpLocust
类,在这个类中定义了模拟用户在执行任务之间应等待的时间,以及哪一个TaskSet
类应定义用户的“行为”。TaskSet
类能够嵌套。
HttpLocust
类继承自Locust
类,而且添加了一个client属性,该属性是HttpSession
的实例,可用于发出HTTP请求。
默认状况下,咱们再也不设置代理以提升性能。若是确实想要测试请求经过HTTP代理,你能够继承HttpLocust
类,并将trust_env字段设置为True。有关更多细节,请参阅请求的文档。
咱们声明任务的另外一种方法(一般更方便)是使用@task装饰器。下面代码与上面的代码效果同样:
1from locust import HttpLocust, TaskSet, task, between
2
3class UserBehaviour(TaskSet):
4 def on_start(self):
5 """ on_start is called when a Locust start before any task is scheduled """
6 self.login()
7
8 def on_stop(self):
9 """ on_stop is called when the TaskSet is stopping """
10 self.logout()
11
12 def login(self):
13 self.client.post("/login", {"username":"ellen_key", "password":"education"})
14
15 def logout(self):
16 self.client.post("/logout", {"username":"ellen_key", "password":"education"})
17
18 @task(2)
19 def index(self):
20 self.client.get("/")
21
22 @task(1)
23 def profile(self):
24 self.client.get("/profile")
25
26class WebsiteUser(HttpLocust):
27 task_set = UserBehaviour
28 wait_time = between(5, 9)
Locust
类(以及HttpLocust
,由于它是一个子类)还容许您指定任务执行之间的等待时间(wait_time = between(5, 9)
)以及其余用户行为。使用between函数,能够在指定的最大值和最小值之间随机选择时间,可是能够经过将wait_time设置为任意函数来使用任何用户定义的时间分布。例如,对于平均时间为1秒的指数分布等待时间:
1import random
2
3class WebsiteUser(HttpLocust):
4 task_set = UserBehaviour
5 wait_time = lambda self: random.expovariate(1)*1000
启动Locust
要使用上述Locust文件运行Locust,若是该文件名为locustfile.py且位于当前工做目录中,则能够运行:$ locust
若是Locust文件位于与locustfile.py在不一样的子目录/或者文件名不同,则使用参数-f
+文件名:$ locust -f locust_files/my_locust_file.py
要在多个进程中运行Locust,咱们能够经过指定--master
:$ locust -f locust_files/my_locust_file.py --master
而后咱们将启动任意数量的从属进程:$ locust -f locust_files/my_locust_file.py --slave
若是要在多台机器上运行Locust,则在启动从属服务器时还必须指定主服务器主机(在单台计算机上运行Locust时不须要,由于主服务器主机默认为127.0.0.1):$ locust -f locust_files/my_locust_file.py --slave --master-host=192.168.0.100
还能够在配置文件(locust.conf或~/.locust.conf)或以LOCUST_前缀的env vars中设置参数
例如:(这将与上一个命令执行相同的操做)$ LOCUST_MASTER_HOST=192.168.0.100 locust
注意:要查看全部可用选项,请键入:locust—help
打开Locust的Web界面
使用上述命令行之一启动Locust后,应打开浏览器并输入http://127.0.0.1:8089或者http://localhost:8089(若是您在本地运行Locust)。而后,你会看到如下界面:
(或者浏览器中访问ipv6本地地址:http://[::1]:8089, 也可)

若是您在逐步负载模式
下运行Locust,,则应该使用如下Locust UI,以下所示:

而后在上述几面中输入数量,以及要访问的URL,点击Start便可看到响应数据,以下图:

Locust--CSV存储测试数据
Locust的测试结果保存到CSV文件,在这种状况下,有两种方法能够执行此操做。
首先,经过Web UI运行Locust时,能够在“Download Data”选项卡下获得CSV文件。
其次,可使用标签运行Locust,该标签将按期保存两个CSV文件。若是计划使用--no-web
标签以自动化方式运行Locust,这将特别有用:
1$ locust -f examples/basic.py --csv=example --no-web -t10m
文件将被命名为example_response_times.csv
和 example_stats.csv
(使用--csv=example
)并记录Locust构建的信息。
若是你想要更快(慢)的写入速度,也能够自动以写入频率:
1import locust.stats
2# 默认为2秒
3locust.stats.CSV_STATS_INTERVAL_SEC = 5
此数据将写入两个文件,并将_response_times.csv
和_stats.csv
添加到你提供的名称中:
1$ cat example_response_times.csv
2"Name","# requests","50%","66%","75%","80%","90%","95%","98%","99%","99.9%","99.99%","100%"
3"GET /",31,4,4,4,4,4,4,4,4,4,4,4
4"/does_not_exist",0,"N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A"
5"GET /stats/requests",38,3,4,4,4,4,5,5,5,5,5,5
6"None Total",69,3,4,4,4,4,4,5,5,5,5,5
和
1$ cat example_stats.csv
2"Type","Name","# requests","# failures","Median response time","Average response time","Min response time","Max response time","Average Content Size","Requests/s"
3"GET","/",51,0,4,3,2,6,12274,0.89
4"GET","/does_not_exist",0,56,0,0,0,0,0,0.00
5"GET","/stats/requests",58,0,3,3,2,5,1214,1.01
6"None","Total",109,56,3,3,2,6,6389,1.89
编写一个locustfile
locustfile是普通的python文件。惟一的要求是至少声明一个类(咱们称之为locust类),该类继承自locust类。
Locust类
一个Locust类表明一个用户(或者一个集群Locust)。Locust将为每一个正在模拟的用户生成(孵化)一个Locust类实例。Locust类一般应该定义一些属性。
task_set属性
task_set属性应该指向一个TaskSet类,这个类定义了用户的行为,下面将对其进行更详细的描述。
wait_time属性
除了task_set属性,还应该声明一个wait_time
方法。它用于肯定模拟用户在执行任务之间将等待多长时间。Locust提供了一些内置的函数,返回一些经常使用的wait_time方法。
最多见的是 between
。它用于使模拟用户在每次执行任务后等待介于最小值和最大值之间的随机时间。其余内置的等待时间函数是constant
和constant_pacing
。
使用如下locustfile,每一个用户将在任务之间等待5到15秒:
1from locust import Locust, TaskSet, task, between
2
3class MyTaskSet(TaskSet):
4 @task
5 def my_task(self):
6 print("executing my_task")
7
8class User(Locust):
9 task_set = MyTaskSet
10 wait_time = between(5, 15)
wait_time方法应该返回秒数(或几分之一秒),也能够在TaskSet类上声明,在这种状况下,它将仅用于该TaskSet。
也能够直接在Locust或TaskSet类上声明本身的wait_time方法。接下来的Locust类将开始休眠1秒钟,而后休眠1秒,2秒,3秒,等等。
1class MyLocust(Locust):
2 task_set = MyTaskSet
3 last_wait_time = 0
4
5 def wait_time(self):
6 self.last_wait_time += 1
7 return self.last_wait_time
weight (权重)属性
若是文件中存在多个locust类,而且命令行中没有指定locust,则每一个新生成的locust将从现有locust中随机选择。不然,你能够从相同的文件中像下面这样指定使用哪一个locust:$ locust -f locust_file.py WebUserLocust MobileUserLocust
若是你想让这些locust中的一个执行得更频繁,你能够给这些类设置一个权重属性。例如,Web用户是mobile用户的三倍:
1class WebUserLocust(Locust):
2 weight = 3
3 ...
4
5class MobileUserLocust(Locust):
6 weight = 1
7 ...
host属性
host属性host属性是要加载的URL前缀(https://cn.bing.com);一般,是在Locust的Web UI或命令行中指定的,在启动Locust时使用--host
。
若是在locust类中声明了一个host属性,则在命令行或Web请求中未指定--host
的状况下将使用该属性。。
TaskSet类
若是Locust类表明蝗虫群,则能够说TaskSet类表明蝗虫的大脑。每一个Locust类必须设置一个task_set属性,该属性指向TaskSet。
顾名思义,TaskSet是任务的集合。这些任务是普通的python可调用对象,而且,若是咱们正在对拍卖网站进行负载测试,则能够完成诸如“加载起始页”,“搜索某些产品”和“竞标”之类的工做。
启动负载测试时,派生的Locust类的每一个实例将开始执行其TaskSet。接下来的状况是每一个TaskSet将选择一个任务并调用它。而后,它将等待Locust类的wait_time方法指定的秒数(除非已直接在TaskSet上声明了wait_time方法,在这种状况下,它将使用本身的方法)。
而后它将再次选择要调用的新任务,再次等待,依此类推。
声明任务
TaskSet声明任务的典型方式是使用task
装饰器。
这里有一个例子:
1from locust import Locust, TaskSet, task
2
3class MyTaskSet(TaskSet):
4 @task
5 def my_task(self):
6 print("Locust instance (%r) executing my_task" % (self.locust))
7
8class MyLocust(Locust):
9 task_set = MyTaskSet
@task使用可选的weight参数,该参数可用于指定任务的执行率。在如下示例中,task2的执行量是task1的两倍:
1from locust import Locust, TaskSet, task
2from locust.wait_time import between
3
4class MyTaskSet(TaskSet):
5 wait_time = between(5, 15)
6
7 @task(3)
8 def task1(self):
9 pass
10
11 @task(6)
12 def task2(self):
13 pass
14
15class MyLocust(Locust):
16 task_set = MyTaskSet
tasks属性
使用@task装饰器来声明任务是一种方便的方法,一般也是最好的方法。可是,也能够经过设置tasks
属性来定义TaskSet的任务(使用@task装饰器实际上只填充tasks属性)。
tasks属性要么是python可调用项的列表,要么是
这些任务是接收一个参数的python可调用函数——正在执行任务的TaskSet类实例。
1from locust import Locust, TaskSet
2
3def my_task(l):
4 pass
5
6class MyTaskSet(TaskSet):
7 tasks = [my_task]
8
9class MyLocust(Locust):
10 task_set = MyTaskSet
若是将tasks属性指定为列表,那么每次执行任务时,都将从tasks属性中随机选择该任务。可是,若是任务是字典(将可调用对象做为键,将整数做为值),则将随机选择要执行的任务,但将int值做为比率。所以,任务看起来像这样:{my_task: 3, another_task: 1}
my_task被执行的可能性是other_task的3倍。
TaskSets可嵌套
TaskSet的一个很是重要的特性是它们能够嵌套,由于真实的网站一般以分层的方式构建,包含多个子部分。所以,嵌套任务集将容许咱们定义一种行为,以更现实的方式来模拟用户。例如,咱们可使用如下结构定义· - ----- TaskSet:
Main user behaviour
Watch movie
Filter movies
Read thread
Reply
New thread
View next page
Index page
Forum page
Browse categories
About page
嵌套TaskSet的方式就像使用task属性指定任务时同样,但不是引用python函数,而是引用另外一个TaskSet:
1class ForumPage(TaskSet):
2 @task(20)
3 def read_thread(self):
4 pass
5
6 @task(1)
7 def new_thread(self):
8 pass
9
10 @task(5)
11 def stop(self):
12 self.interrupt()
13
14class UserBehaviour(TaskSet):
15 tasks = {ForumPage:10}
16
17 @task
18 def index(self):
19 pass
所以,在上面的示例中,若是在执行UserBehaviour TaskSet时选择了要执行的ForumPage,则ForumPage TaskSet将开始执行。而后,ForumPage TaskSet将选择其本身的任务之一,执行它,等待,依此类推。
关于上述示例,须要注意一点,那就是在ForumPage的stop方法中调用self.interrupt()。这样作其实是中止执行ForumPage任务集,并在UserBehaviour实例中继续执行。若是咱们在ForumPage的某处没有调用interrupt()方法,Locust将永远不会中止运行已经启动的ForumPage任务。可是经过使用中断功能,咱们能够与任务权重一块儿定义模拟用户离开论坛的可能性。
也可使用@task装饰器在类中内联声明嵌套的TaskSet,就像声明普通任务时同样:
1class MyTaskSet(TaskSet):
2 @task
3 class SubTaskSet(TaskSet):
4 @task
5 def my_task(self):
6 pass
引用Locust实例,或父TaskSet实例
TaskSet实例的属性locust指向它的locust实例,属性parent指向它的父TaskSet(它将在基本TaskSet中指向Locust实例)。
TaskSequence类
TaskSequence类是一个TaskSet,可是它的任务是按顺序执行的。
要定义此顺序,您应该执行如下操做:
1 @seq_task(1)
2 def first_task(self):
3 pass
4
5 @seq_task(2)
6 def second_task(self):
7 pass
8
9 @seq_task(3)
10 @task(10)
11 def third_task(self):
12 pass
在上面的示例中,执行顺序定义为先执行first_task,而后执行second_task,最后执行Third_task 10次。能够看到,可使用@task装饰器组合@seq_task,固然也能够将TaskSet嵌套在TaskSequences中,反之亦然。
Setups, Teardowns, on_start, 和on_stop
Locust还支持Locust级setup
和teardown
,TaskSet级setup
和teardown
,TaskSet
'、 on_start
和on_stop
.
Setups 和 Teardowns
setup
和teardown
,不管是在Locust
仍是TaskSet
上运行,都是只运行一次的方法。setup
是在任务开始运行以前运行,而teardown
是在全部任务完成并退出Locust以后运行的。这使你可以在Locust任务运行以前执行一些准备工做(如建立数据库),并在Locust退出以前进行清理(如删除数据库)。
要使用它,只需在Locust或TaskSet类上声明一个setup或teardown。这些方法将为你运行。
on_start和on_stop方法
TaskSet类能够声明on_start
方法或on_stop
方法。
当模拟用户开始执行该TaskSet类时,将调用on_start
方法;而当TaskSet中止时,将调用on_stop <locust.core.TaskSet.on_stop()
方法。
事件顺序
因为许多设置和清除操做是相互依赖的,所以如下是它们的执行顺序:
Locust setup (一次)
TaskSet setup (一次)
TaskSet on_start (每一个locust一次)
TaskSet tasks…
TaskSet on_stop (每一个locust一次)
TaskSet teardown (一次)
Locust teardown (一次)
一般,setup和teardown方法应该是互补的。
发送HTTP请求
到目前为止,咱们仅介绍了Locust用户的任务调度部分。为了实际测试系统,咱们须要发送HTTP请求。为了帮助咱们作到这一点,存在HttpLocust
类。当使用这个类时,每一个实例得到一个client属性,该属性将是HttpSession的一个实例,可用于发送HTTP请求。
HttpLocust类
表示一个HTTP“用户”,该“用户”将被孵化并攻击要加载测试的系统。
此用户的行为由task_set属性定义,该属性应指向TaskSet
类。
该类在实例化时建立一个client属性,该属性是一个HTTP client ,支持在请求之间保持用户会话。
client= None
在Locust实例化后建立的HttpSession实例。客户端支持cookie,所以在HTTP请求之间的会话。
在继承HttpLocust类时,咱们可使用它的client属性对服务器发出HTTP请求。
这是一个Locust文件的例子,能够用两个URL负载测试站点 ;/ 和 /about/:
1from locust import HttpLocust, TaskSet, task, between
2
3class MyTaskSet(TaskSet):
4 @task(2)
5 def index(self):
6 self.client.get("/")
7
8 @task(1)
9 def about(self):
10 self.client.get("/about/")
11
12class MyLocust(HttpLocust):
13 task_set = MyTaskSet
14 wait_time = between(5, 15)
使用上面的Locust类,每一个模拟用户将在请求之间等待5到15秒,而且 / 被请求的时间将是 /about/ 的两倍。
细心的读者会发现奇怪的是,咱们可使用TaskSet中的self.client而不是self.locust.client来引用HttpSession实例。咱们能够这样作是由于TaskSet
类有一个方便的属性client,该属性仅返回self. custt .client。
使用HTTP客户端
HttpLocust的每一个实例在client属性中都有一个HttpSession
实例。HttpSession类其实是request.Session
的子类,可用于发出HTTP请求,该请求将使用get,post,put,put,delete,head,patch和options方法将其统计数据报给Locust。HttpSession实例将在请求之间保存cookie,以便用于登陆网站并在请求之间保持会话。也能够从Locust实例的TaskSet实例中引用client属性,以便轻松地检索客户端并发出HTTP请求。
下面是一个简单的示例,它向 / about 路径发出GET请求(在这种状况下,咱们假设self是TaskSet
或HttpLocust
类的实例:
1response = self.client.get("/about")
2print("Response status code:", response.status_code)
3print("Response content:", response.text)
这里有一个POST请求的例子:
1response = self.client.post("/login",
2 {"username":"testuser",
3 "password":"secret"}
4 )
安全模式
HTTP客户端配置为以safe_mode运行。这样作的目的是,因为链接错误、超时或相似缘由而失败的任何请求都不会引起异常,而是返回一个空的虚拟Response对象。该请求将在Locust的统计信息中标记为失败。返回的虚拟Response的content属性将设置为None,其status_code=0。
手动控制请求是成功仍是失败
默认状况下,除非HTTP响应代码为OK(<400),不然请求将被标记为失败的请求。大多数状况下,此默认值是你想要的。可是,有时(例如,在测试URL端点时,你指望返回404,或者在测试一个设计糟糕的系统时,即便出现错误也可能返回200 OK)——须要手动控制Locust是否应该将请求标记为成功或失败。
经过使用catch_response参数和with语句,即便响应代码正确,也能够将请求标记为失败:
1with self.client.get("/", catch_response=True) as response:
2 if response.content != b"Success":
3 response.failure("Got wrong response")
正如能够将具备OK响应代码的请求标记为失败同样,也能够将catch_response参数与with语句一块儿使用,以标记致使HTTP错误代码的请求在统计中仍被报告为成功:
1with self.client.get("/does_not_exist/", catch_response=True) as response:
2 if response.status_code == 404:
3 response.success()
将带有动态参数的URL请求分组
网站的url包含一些动态参数的页面是很常见的。一般在Locust的统计信息中将这些URL分组在一块儿是颇有意义的。这能够经过将名称参数传递给HttpSession的不一样请求方法来完成。
例如:
1# 这些请求的统计数据将纳入如下类别: /blog/?id=[id]
2for i in range(10):
3 self.client.get("/blog?id=%i" % i, name="/blog?id=[id]")
公共库--Common libraries
一般,将共享公共库的多个locustfiles分组。在这种状况下,在项目中根目录定义为调用Locust的目录很是重要,建议全部的locust文件都位于项目根目录下。
平面文件结构以下:
project root
commonlib_config.py
commonlib_auth.py
locustfile_web_app.py
locustfile_api.py
locustfile_ecommerce.py
locustfile可使用如下命令导入公共库,例如:import commonlib_auth
。可是,这种方法并不能清楚地将公共库与Locust文件分开。
子目录能够是一种更简洁的方法(请参见下面的示例),但locust只导入与运行的locustfile所在目录相关的模块。若是但愿从项目根目录(即运行locust命令的位置)导入,请确保在loucst文件导入任何公共库以前编写sys.path.append(os.getcwd())
,这将使项目根目录(即当前工做目录)可导入。
project root
init.py
common/
`init.py`
`config.py`
`auth.py`
locustfiles/
`init.py`
`web_app.py`
`api.py`
`ecommerce.py`
经过以上项目结构,locust文件可使用如下方法导入公共库:
1sys.path.append(os.getcwd())
2import common.auth
Locust--分布式运行
若是一台计算机不足以模拟所需的用户数量,那么Locust将支持运行分布在多台计算机上的负载测试。
可使用--master
标志在主模式下启动Locust的一个实例。这个实例将运行Locust的web接口,您能够在这里启动测试并实时查看统计信息。主节点自己不模拟任何用户。相反,您必须使用--slave
标志启动一个或多个从Locust节点,与--master-host
(指定主节点的IP /主机名)一块儿使用。
常见的设置是在一台机器上运行一个主程序,而后在从计算机上每一个处理器内核运行一个从属实例。
注意:
在运行Locust分布式系统时,主计算机和每一个从属计算机都必须具备蝗虫测试脚本的副本。
当分布式运行的时候,建议启动的模拟用户数量要大于
Locust类的数量X从机的数量
。
不然,因为当前的实现,可能会获得与Locust类的weight
属性不对应的Locust类分布。
并且,若是孵化率低于从属节点的数量,则孵化将在“突发”中发生,其中全部从属节点将孵化单个用户,而后休眠数秒钟,孵化另外一个用户,休眠并重复。
例如:
要在master模式下启动Locust:locust -f my_locustfile.py --master
选项--master
将Locust设置为主模式, web接口将在此节点上运行。
-- slave
将Locust设置为从属模式。
--master-host=X.X.X.X
可选,与-- slave
一块儿使用,设置主节点的主机名/IP(默认为127.0.0.1)
--master-port=5557
可选,与-- slave
一块儿使用,用于设置主节点的端口号(默认为5557)。
注意,locust将使用指定的端口,以及端口号+1。所以,若是使用5557,则locust将同时使用端口5557和5558。
--master-bind-host=X.X.X.X
可选,与-- master
一块儿使用。肯定主节点将绑定到哪一个网络接口。默认为*(全部可用的接口)。
--master-bind-port=5557
可选,与-- master
一块儿使用。肯定主节点将监听的网络端口。默认为5557。
注意,locust将使用指定的端口,以及端口号+1。所以,若是使用5557,则locust将同时使用端口5557和5558。
--expect-slaves=X
使用--no-web
启动主节点时使用。而后,主节点将一直等到链接了X个从节点以后才开始测试。
使用Docker进行分布式运行
详见 性能测试Locust--(5)Docker运行 [详见后文]
非UI模式下分布式运行Locust
详见 性能测试Locust--(6)非UI模式下分布式运行Locust [详见后文]
逐步负载模式下分布式运行Locust
详见 性能测试Locust--(4)逐步负载模式 [详见后文]
提升蝗虫的性能
若是你打算运行大规模负载测试,你可能会对使用Locust附带的备用HTTP client 感兴趣。
详见 [Increase Locust’s performance with a faster HTTP client]
https://docs.locust.io/en/stable/increase-performance.html#increase-performance
Locust--逐步负载模式
若是想在不一样的用户负载下监控服务性能,并探测能够实现的最大tps,能够在启用“逐步负载”模式运行Locust--stp-load
1$ locust -f locust_files/my_locust_file.py --step-load
选项
--step-load
启用“Step Load--逐步负载”模式, 以监视当用户负载增长时性能指标如何变化。
--step-clients
在“逐步负载”模式下,客户端数量逐步增长。与--step-load
一块儿使用。
--step-time
在“逐步负载”模式下,每一个Step的进持续时间,例如(300s,20m,3h,1h30m等)。与--step-load
一块儿使用。
Locust在非Web UI的状况下“逐步负载”模式运行
若是要在没有Web UI的状况下以逐步负载方式运行Locust,则可使用--step-clients
和--step-time
来执行此操做:
1$ locust -f --no-web -c 1000 -r 100 --run-time 1h30m --step-load --step-clients 300 --step-time 20m
Locust 将逐步蜂拥而至,一旦时间到了,将关闭它们。
Locust在逐步负载模式下分布式运行
若是你想要在逐步负载模式下分布式运行Locust,你应该在启动主节点时指定--step-load
选项,来分步式汇集locust。而后在Locust UI中将显示 --step-cients
选项和 --step-time
选项。
Locust--Docker运行Locust
为了简单起见,咱们提供了一个能够独立运行的Docker映像,能够做为主映像,也能够做为从映像。
环境变量
LOCUST_MODE
standalone、master 或者 slave。
默认是standalone。LOCUSTFILE_PATH
容器内部到locustfile的路径。默认为/locustfile.py
.LOCUST_MASTER_HOST
master的主机名。LOCUST_MASTER_PORT
与master通讯的端口。默认为5557LOCUST_OPTS
传递给Locust的其余选项。默认为''
运行测试
运行测试最简单的方法是使用内置的测试文件构建映像。一旦编写了locustfile,就可使用一个简单的Dockerfile
将其打包到Docker映像中:
须要将构建的映像推送到Dockerhub,AWS ECR或GCR等Docker存储库中,以便分布式基础架构可以提取该镜像。请参阅所选存储库的文档,以了解如何经过存储库进行身份验证以获取镜像。
为了在本地调试,您能够运行一个容器并将locustfile做为volume传递进来:
要在没有Web UI的独立模式下运行,可使用LOCUST_OPTS
环境变量添加所需的选项:
若是您是Kubernetes用户,则可使用[Helm chart]
https://github.com/helm/charts/tree/master/stable/locust
Locust--非UI模式下运行Locust
能够在没有Web UI的状况下运行Loccust.
例如,若是要以某种自动化流程(例如CI服务器)运行Locust,经过使用--no-web
标记和-c
和-r
:
1$ locust -f locust_files/my_locust_file.py --no-web -c 1000 -r 100
-c
指定要生成的Locust用户数;-r
指定孵化率(每秒产生的用户数)。
为测试设置时间限制
若是要指定测试的运行时间,可使用 --run-time
或者 -t
:
1$ locust -f --no-web -c 1000 -r 100 --run-time 1h30m
一旦时间到,Locust将关闭。
容许任务在关闭时完成其迭代
默认状况下,Locust将当即中止任务。若是想让任务完成迭代,则可使用--stop-timeout <seconds>
。
1$ locust -f --no-web -c 1000 -r 100 --run-time 1h30m --stop-timeout 99
非Web UI的状况下分布式运行Locust
在非UI状况下想分布式运行Locust,应该在启动主节点时指定--expect-slaves
选项,指定但愿链接的从节点的数量。而后,将一直等到链接了诸多从节点以后才开始测试。
Locust--使用更快的HTTP client提升Locust性能
Locust默认的HTTP客户端使用python-requests。由于requests是一个维护良好的python程序包,它提供了许多python开发人员都熟悉的优质API。所以,在许多状况下,建议使用使用请求的默认HttpLocust
。
可是,若是计划运行大规模的测试,Locust提供了一个替代的HTTP 客户端 FastHttpLocust
,它使用geventhttpclient而不是requests。
该客户端的速度明显提升,其性能是HTTP-requests的5 ~ 6倍。这并不必定意味着每一个CPU内核能够模拟的用户数量将自动增长5 ~ 6倍,由于这还取决于负载测试脚本。
总之,若是你的Locust脚本在执行HTTP-requests时花费了大量的CPU时间,那么你可能会看到显著的性能提高。
如何使用FastHttpLocust
代替HttpLocust的子类是FastHttpLocust:
1from locust import TaskSet, task, between
2from locust.contrib.fasthttp import FastHttpLocust
3
4class MyTaskSet(TaskSet):
5 @task
6 def index(self):
7 response = self.client.get("/")
8
9class MyLocust(FastHttpLocust):
10 task_set = MyTaskSet
11 wait_time = between(1, 60)
注意
与默认python-requests的HttpLocust相比,FastHttpLocust使用一个彻底不一样的API实现另外一个HTTP client 。所以,取决于如何使用HttpClient,FastHttpLocust可能没法替代HttpLocust。
在FastHttpLocust的客户端实现中,SSL域名检查被关闭。所以,它将容许经过无效的SSL证书而不会产生任何问题。
API
FastHttpSession类
classFastHttpSession(base_url, **kwargs)
init(base_url, **kwargs) | x.init(…) 初始化X,详见 help |
get(path, **kwargs) | 发送GET请求 |
head(path, **kwargs) | 发送HEAD请求 |
options(path, **kwargs) | 发送OPTION请求 |
patch(path, data=None, **kwargs) | 发送PATCH请求 |
post(path, data=None, **kwargs) | 发送POST请求 |
put(path, data=None, **kwargs) | 发送PUT请求 |
request(method, path, name=None, data=None, catch_response=False, stream=False, headers=None, auth=None, **kwargs)
发送HTTP请求并返回locust.contrib.fasthttp.FastResponse
对象.
Parameters:
method --建立新Request对象方法。
path --Path将与已指定的base host URL链接。也能够是完整URL,在这种状况下,将请求完整URL,而且忽略host。
name --可选,在Locust的统计信息中能够指定一个参数做为标签,而不是URL路径。这可用于将请求的不一样URL分组到Locust的统计信息中的单个条目中。
catch-response --可选,Boolean,若是设置了Boolean参数,可用于使请求返回上下文管理器,以用做with语句的参数。即便响应代码正常(2xx),也能够根据响应的内容将请求标记为失败。
反之亦然,即便没有响应代码(即500或404),也可使用catch_response来捕获请求,而后将其标记为成功。data -- 可选,请求体-body, Dict或bytes
headers -- 可选,请求头,Dict
auth -- 可选,验证(用户名,密码)元组,以启用基本HTTP验证。
stream -- 可选,若是设置为true,则不会当即使用响应主体,而是能够经过访问Response对象上的stream属性来使用它。
将流设置为True的另外一个做用是:不会将下载响应内容的时间记录到Locust报告中的请求时间。
classFastResponse(ghc_response, request=None, sent_request=None)
content
Unzips, 若有必要,并缓冲接收到的Body. 当心大文件!
headers= None
相似于Dict的对象,包含响应标头
text
以解码字符串的形式返回响应的文本内容(python2上的unicode)
Locust--CSV存储测试数据
Locust的测试结果保存到CSV文件,在这种状况下,有两种方法能够执行此操做。
首先,经过Web UI运行Locust时,能够在“Download Data”选项卡下获得CSV文件。
其次,可使用标签运行Locust,该标签将按期保存两个CSV文件。若是计划使用--no-web
标签以自动化方式运行Locust,这将特别有用:
1$ locust -f examples/basic.py --csv=example --no-web -t10m
文件将被命名为example_response_times.csv
和 example_stats.csv
(使用--csv=example
)并记录Locust构建的信息。
若是你想要更快(慢)的写入速度,也能够自动以写入频率:
1import locust.stats
2# 默认为2秒
3locust.stats.CSV_STATS_INTERVAL_SEC = 5
此数据将写入两个文件,并将_response_times.csv
和_stats.csv
添加到你提供的名称中:
1$ cat example_response_times.csv
2"Name","# requests","50%","66%","75%","80%","90%","95%","98%","99%","99.9%","99.99%","100%"
3"GET /",31,4,4,4,4,4,4,4,4,4,4,4
4"/does_not_exist",0,"N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A"
5"GET /stats/requests",38,3,4,4,4,4,5,5,5,5,5,5
6"None Total",69,3,4,4,4,4,4,5,5,5,5,5
和
1$ cat example_stats.csv
2"Type","Name","# requests","# failures","Median response time","Average response time","Min response time","Max response time","Average Content Size","Requests/s"
3"GET","/",51,0,4,3,2,6,12274,0.89
4"GET","/does_not_exist",0,56,0,0,0,0,0,0.00
5"GET","/stats/requests",58,0,3,3,2,5,1214,1.01
6"None","Total",109,56,3,3,2,6,6389,1.89
使用定制的客户端测试其余系统
以HTTP为主要目标构建Locust。可是,经过编写触发request_success
和request_failure
事件的自定义客户端,能够很容易的将其扩展,用来对任何基于request/response
的系统进行负载测试。
Locust client示例--XML-RPC
如下是Locust类XmlRpcLocust
的示例,该类提供XML-RPC客户端XmlRpcClient并跟踪全部发出的请求:
1import time
2import xmlrpclib
3
4from locust import Locust, TaskSet, events, task, between
5
6
7class XmlRpcClient(xmlrpclib.ServerProxy):
8 """
9 Simple, sample XML RPC client implementation that wraps xmlrpclib.ServerProxy and
10 fires locust events on request_success and request_failure, so that all requests
11 gets tracked in locust's statistics.
12 """
13 def __getattr__(self, name):
14 func = xmlrpclib.ServerProxy.__getattr__(self, name)
15 def wrapper(*args, **kwargs):
16 start_time = time.time()
17 try:
18 result = func(*args, **kwargs)
19 except xmlrpclib.Fault as e:
20 total_time = int((time.time() - start_time) * 1000)
21 events.request_failure.fire(request_type="xmlrpc", name=name, response_time=total_time, exception=e)
22 else:
23 total_time = int((time.time() - start_time) * 1000)
24 events.request_success.fire(request_type="xmlrpc", name=name, response_time=total_time, response_length=0)
25 # In this example, I've hardcoded response_length=0. If we would want the response length to be
26 # reported correctly in the statistics, we would probably need to hook in at a lower level
27
28 return wrapper
29
30
31class XmlRpcLocust(Locust):
32 """
33 This is the abstract Locust class which should be subclassed. It provides an XML-RPC client
34 that can be used to make XML-RPC requests that will be tracked in Locust's statistics.
35 """
36 def __init__(self, *args, **kwargs):
37 super(XmlRpcLocust, self).__init__(*args, **kwargs)
38 self.client = XmlRpcClient(self.host)
39
40
41class ApiUser(XmlRpcLocust):
42
43 host = "http://127.0.0.1:8877/"
44 wait_time = between(0.1, 1)
45
46 class task_set(TaskSet):
47 @task(10)
48 def get_time(self):
49 self.client.get_time()
50
51 @task(5)
52 def get_random_number(self):
53 self.client.get_random_number(0, 100)
若是你之前编写过 Locust的测试,你应该知道一个名为 ApiUser 的类,它是一个普通的 Locust 类,它的 task_set属性是一个 TaskSet 类的子类,而这个子类带有多个 task。
然而,ApiUser 继承自 XmlRpcLocust,您能够在 ApiUser 的正上方看到它。XmlRpcLocust 类在 client 属性下提供 XmlRpcClient 的实例。XmlRpcClient 是标准库的 xmlrclib. serverproxy
的装饰器。它基本上只是代理函数调用,可是添加了触发用于将全部调用报告给 Locust 统计数据的 locust.events.request_success
和 locust.events.request_failure
的重要功能。
下面是 XML-RPC 服务器的实现,它能够做为上述代码的服务器:
1import random
2import time
3from SimpleXMLRPCServer import SimpleXMLRPCServer
4
5
6def get_time():
7 time.sleep(random.random())
8 return time.time()
9
10def get_random_number(low, high):
11 time.sleep(random.random())
12 return random.randint(low, high)
13
14server = SimpleXMLRPCServer(("localhost", 8877))
15print("Listening on port 8877...")
16server.register_function(get_time, "get_time")
17server.register_function(get_random_number, "get_random_number")
Locust--Locust API以及延伸扩展--0.14.4
Locust延伸扩展
Locust附带了不少事件,这些事件提供了以不一样方式扩展Locust的钩子(hooks )。
事件监听器能够在模块级注册到Locust文件中。这里有一个例子:
1from locust import events
2
3def my_success_handler(request_type, name, response_time, response_length, **kw):
4 print "Successfully fetched: %s" % (name)
5
6events.request_success += my_success_handler
注意:
强烈建议你在侦听器中添加通配符关键字参数(上面代码中的** kw),以防止在之后的版本中添加新参数时代码崩溃。
要查看全部可用事件,请参阅事件[挂钩](https://docs.locust.io/en/stable/api.html#events)。
添加网络路由
Locust使用Flask来提供Web UI,所以很容易将Web端点添加到Web UI。只需将Flask应用程序导入您的locustfile并设置一条新路径:
1from locust import web
2
3@web.app.route("/added_page")
4def my_added_page():
5 return "Another page"
如今应该可以启动locust并浏览到:http://127.0.0.1:8089/added_page
Locust日志记录
Locust附带有基本的日志记录配置,该配置能够选择使用--loglevel
和/或--logfile
来修改配置。若是要控制日志记录配置,则能够提供--skip-log-setup
标志,该标志将忽略其余参数。
Options选项
--skip-log-setup
禁用Locust的日志记录设置。相反,配置是由Locust test或Python默认设置提供配置。
--loglevel
在DEBUG/INFO/WARNING/ERROR/CRITICAL之间选择。默认值为INFO。简写为-L
。
--logfile
日志文件的路径。若是未设置,则日志将转到stdout / stderr。
Locust API
API的话以官网为准,如下是官网连接
API 官网连接 :https://docs.locust.io/en/stable/api.html
Locust 类
class Locust
表示一个策划并将要对系统进行负载测试的“用户”。
此用户的行为由task_set
属性定义,该属性应该指向TaskSet类。
此类一般应由定义某种客户端的类继承。例如,在对HTTP系统进行负载测试时,您可能但愿使用HttpLocust
类。task_set= None
TaskSet类,定义此Locust的执行行为
wait_time= None
该方法,返回执行Locust任务之间的时间(以秒为单位)。能够为单个TaskSet覆盖。
例如:
1from locust import Locust, between
2class User(Locust):
3 wait_time = between(3, 25)
weight= 10
Locust被选中执行的几率。权重越高,被选中的机会越大。
HTTPLocust 类
class HttpLocust
表示一个策划并将要对系统进行负载测试的HTTP“用户”。
该HTTP用户的行为由task_set
属性定义,该属性应该指向TaskSet
类。
这个类在实例化时会建立一个 client 属性,这个属性的值是一个支持在请求间保持用户会话(user session)的 HTTP 客户端。
client=None
在 locust 实例化时建立的 HttpSession 实例。客户端支持 cookies,所以在 HTTP 请求间保持会话。
TaskSet类
class TaskSet(parent)
该类定义locust
用户将要执行的一组任务。
当 TaskSet开始运行时,它将从 tasks 属性中选择一个任务并执行,而后调用这个任务的 wait_function 方法,以后再调用另外一个任务,以此类推。
其中 wait_function 方法定义并返回一个以毫秒为单位的睡眠时间,wait_function 方法定义的睡眠时间的默认是介于 min_wait 和 max_wait 之间且均匀分布的随机数;而后它将调度另外一个任务执行,等等。
TaskSets能够嵌套,这意味着一个 TaskSet 的 tasks 属性能够包含其余的 TaskSet。若是计划执行嵌套的 TaskSet ,则将实例化它并从当前执行的 TaskSet 进行调用。而后,当前运行的 TaskSet 中的执行将被移交给嵌套的 TaskSet ,嵌套的 TaskSet 将继续运行,直到遇到由 TaskSet.interrupt()
方法抛出的 InterruptTaskSet 异常时终止。(而后在第一个任务集中继续执行)。
client
引用根Locust
实例的client属性。
interrupt(reschedule=True)
中断TaskSet并将执行控制移交给父TaskSet。
若是reschedule
的值为True,父 locust 将当即从新调度并执行下一个任务。
这个方法不该该由根 TaskSet(即当即附加到 Locust 类的 task_set 属性)调用,而应该由层次结构中更深层次的嵌套 TaskSet 类调用。
locust= None
当TaskSet实例化后,会引用根Locust类实例。
parent= None
实例化TaskSet时,将引用父TaskSet或Locust类实例。对于嵌套TaskSet类颇有用。
schedule_task(task_callable, args=None, kwargs=None, first=False)
将任务添加到Locust的任务执行队列中。
参数:
task_callable: 要调度的Locust任务计划表
args: 将传递给可调用任务(task_callable)的参数
kwargs: 关键字字典参数,将传递给可调用(task_callable)的任务.
first: 可选关键字参数。若是为 True,任务会被放到队列的首位。
tasks= []
列表中包含表示 locust 用户任务的可调用对象。
若是该参数值是一个列表,那么将从中随机挑选任务进行执行。
若是该参数值是一个元素为二元组 (callable, int) 的列表或元素为 callable: int 的字典,那么将随机选择要执行的任务,可是每一个任务将根据其对应的 int 类型的值进行加权。因此在下面的例子中,ThreadPage 被选中的可能性是 write_post 的15倍:
1class ForumPage(TaskSet):
2 tasks = {ThreadPage:15, write_post:1}
wait_time()
该方法返回执行任务之间的时间(以秒为单位)。
例如:
1from locust import TaskSet, between
2class Tasks(TaskSet):
3 wait_time = between(3, 25)
任务装饰器 task decorator
task(weight=1)
使用一个便捷装的饰器,以便可以为类中的TaskSet内联声明任务。
1class ForumPage(TaskSet):
2 @task(100)
3 def read_thread(self):
4 pass
5
6 @task(7)
7 def create_thread(self):
8 pass
TaskSequence类(任务序列类)
classTaskSequence(parent)
定义 locust 用户将要执行的任务序列。
当 TaskSequence 开始执行时,它将从 tasks 属性值中根据任务的索引选择一个任务进行执行,而后调用它的定义了一个睡眠时间的 wait_fucntion 方法。wait_function 定义的睡眠时间默认为介于 min_wait 和 max_wait 之间且均匀分布的一个随机数,单位为毫秒。而后再调用索引为 index + 1 / % 的任务,以此类推。
TaskSequence 能够与 TaskSet 嵌套,这意味着 TaskSequence 的 tasks 属性能够包含 TaskSet 实例和其余TaskSequence 实例。若是计划执行嵌套的 TaskSet,则将实例化它并从当前执行的 TaskSet 调用它。而后,当前运行的 TaskSet 中的执行将被移交给嵌套的 TaskSet ,这个嵌套的 TaskSet 将继续运行,直到遇到由 TaskSet.interrupt()
抛出 InterruptTaskSet
异常时终止,而后在第一个 TaskSet 中继续执行。
在这个类中,任务应该被定义成一个列表,或者简单地由 @task_seq 装饰器定义。
client
引用根 Locust 实例的client
属性。
interrupt(reschedule=True)
中断 TaskSet 并将执行控制权交给父 TaskSet。
若是 reschedule 的值为 True,父 locust 将当即从新调度并执行下一个任务。
这个方法不该该由根 TaskSet (即当即附加到 Locust 类的 task_set 属性)调用,而应该由层次结构中更深层次的嵌套 TaskSet 类调用。
schedule_task(task_callable, args=None, kwargs=None, first=False)
添加一个任务到Locust 的任务执行队列。
参数:
task_callable:要调度的 locust 任务。
args:要传递给 task_callable 的参数。
kwargs:要传递给 task_callable 的关键字参数的字典。
first:可选关键字参数。若是为 True,任务会被放到队列的首位。
wait_time()
该方法返回执行任务之间的时间(以秒为单位)。
例如:
1from locust import TaskSet, between
2class Tasks(TaskSet):
3 wait_time = between(3, 25)
seq_task装饰器
seq_task(order)
用于在类中内联声明 TaskSequence 的任务。
例如:
1class NormalUser(TaskSequence):
2 @seq_task(1)
3 def login_first(self):
4 pass
5
6 @seq_task(2)
7 @task(25) # You can also set the weight in order to execute the task for `weight` times one after another.
8 def then_read_thread(self):
9 pass
10
11 @seq_task(3)
12 def then_logout(self):
13 pass
HttpSession 类
between(min_wait, max_wait)
返回一个函数,该函数将在min_wait和max_wait之间返回一个随机数。
例如:
1class User(Locust):
2 # wait between 3.0 and 10.5 seconds after each task
3 wait_time = between(3.0, 10.5)
constant(wait_time)
返回一个函数,该函数只返回wait_time参数指定的数字。
例如:
1class User(Locust):
2 wait_time = constant(3)
constant_pacing(wait_time)
返回一个函数,该函数将跟踪任务的运行时间,每次调用它时,它将返回一个等待时间,该等待时间将尝试使任务执行之间的总时间等于wait_time参数指定的时间。
在如下示例中,不管任务执行时间如何,任务老是每秒执行一次:
1class User(Locust):
2 wait_time = constant_pacing(1)
3 class task_set(TaskSet):
4 @task
5 def my_task(self):
6 time.sleep(random.random())
若是任务执行超过了指定的wait_time,则在开始下一个任务以前的等待时间为0。
HttpSession 类
**class HttpSession(base_url, *args, *kwargs)*
用于执行Web请求和在请求之间保留(会话)Cookie的类(以便可以登陆和注销网站)。每一个请求都被记录下来,以便Locust能够显示统计信息。
这是Python的 requests 库的requests.Session
类的拓展,工做原理与是极其类似的。然而,发送请求的方法(get、post、delete、put、head、options、patch、request)如今能够接受一个 url 参数,这个参数只是 URL的路径部分,在这种状况下,URL的主机部分将取 HttpSession.base_url (继承自一个 Locust 类的 host 属性)的值。
发送请求的每一个方法还接受两个额外的可选参数,这些参数是特定于 Locust ,在Python的 requests 库中不存在的:
参数:
name
可选参数。能够指定为 Locust 的统计信息中的标签,用于代替 URL 路径。这能够用于将被请求的不一样 URL 分组到 Locust 统计数据中的一个条目中。catch_response
可选参数。若是要设置,能够是一个布尔值。能够用来使请求返回为做为with 语句的参数的上下文管理器。这将容许根据响应内容将请求标记为失败,即便响应代码是 ok (2xx) ,反之亦然。可使用 catch_response 捕捉请求,而后将其标记为成功,即便响应代码不是 ok (例如 500 或 404)。
__init__(base_url, \*args, \*\* kwargs)
x.init(…) 初始化x; see help(type(x)) for signature
delete(url, \*\*kwargs)
发送一个 DELETE 请求,返回一个 Response 对象。
参数:
url:新 Request 对象的URL。
**kwargs:request 的可选参数。
返回值类型:requests.Response 对象。
get(url, \*\*kwargs)
发送一个 GET 请求,返回一个 Response 对象。
参数:
url:新 Request 对象的URL。
**kwargs:request 的可选参数。
返回值类型:requests.Response 对象。
head(url, \*\*kwargs)
发送一个 HEAD 请求,返回一个 Response 对象。
参数:
url:新 Request 对象的URL。
**kwargs:request 的可选参数。
返回值类型:requests.Response 对象。
options(url, \*\*kwargs)
发送一个 OPTIONS 请求,返回一个 Response 对象。
参数:
url:新 Request 对象的URL。
**kwargs:request 的可选参数。
返回值类型:requests.Response 对象。
patch(url,data=None , \*\*kwargs)
发送一个 PATCH 请求,返回一个 Response 对象。
参数:
url:新 Request 对象的URL。
data:可选参数。发送到请求主体中的字典、bytes 或 file-like 对象。
**kwargs:request 的可选参数。
返回值类型:requests.Response 对象。
post(url,data=None , json=None, \*\*kwargs)
发送一个 POST 请求,返回一个 Response 对象。
参数:
url:新 Request 对象的URL。
data:可选参数。发送到请求主体中的字典、bytes 或 file-like 对象。
**kwargs:request 的可选参数。
json:可选参数。要发送到请求主体中的 json 格式数据。
返回值类型:requests.Response 对象。
put(url,data=None , \*\*kwargs)
发送一个 PUT 请求,返回一个 Response 对象。
参数:
url:新 Request 对象的URL。
data:可选参数。发送到请求主体中的字典、bytes 或 file-like 对象。
**kwargs:request 的可选参数。
返回值类型:requests.Response 对象。
request(method, url, name=None , catch_response=False, **kwargs)
构造并发送一个requests.Request
。返回 requests.Response
对象。
参数:
method:新 Request 对象的方法。
url:新 Request 对象的URL。
name:可选参数。
能够指定为 Locust 的统计信息中的标签,用于代替 URL 路径。这能够用于将被请求的不一样 URL 分组到 Locust 统计数据中的一个条目中。
catch_response可选参数。若是要设置,能够是一个布尔值。能够用来使请求返回为做为with 语句的参数的上下文管理器。这将容许根据响应内容将请求标记为失败,即便响应代码是 ok (2xx) ,反之亦然。可使用 catch_response捕捉请求,而后将其标记为成功,即便响应代码不是 ok (例如 500 或 404)。
params:可选参数。要发送到Request
的查询字符串的字典或 bytes 对象。
data:可选参数。要发送到 Request
主体中的字典或 bytes 对象。
headers:可选参数。与 Request
一块儿发送的表示 HTTP headers 的字典。
cookies:可选参数。与 Request
一块儿发送的表示 cookies 的 dict 或 CookieJar 对象。
files:可选参数。用于多部分编码上传的元素为 filename: filename: file-like-objects
的字典。
auth:可选参数:用于启用 Basic/Digest或自定义的 HTTP Auth 的元组或可调用对象。
timeout:可选参数。以浮点数或(链接超时、读取超时)元组的形式等待服务器发送数据的时间(以秒为单位)。
allow_redirects:可选参数。布尔类型。默认值为 True。表示是否容许重定向。
proxies:可选参数。字典类型。键表示代理使用的协议,键值表示代理的URL。
stream:可选参数。是否当即下载响应内容。默认值为 False
。
verify:可选参数。若是为True
,则会验证 SSL 证书。也能够提供一个 CA_BUNDLE 路径。
cert:可选参数。若是提供一个字符串。那么应该是指向SSL 客户端证书(.pem文件)的路径;若是是一个元组,则应该是 (‘cert’, ‘key’)。
Response类
这个类实际上是位于python-requests库中的,可是因为 Locust在构造HTTP 请求的时候要用到这个类,而且在编写 Locust负载测试时,这个类也很是重要,因此就把这个类包含在了 API 文档里。您还能够查看请求文档中的Response
类。
class ResponseResponse
对象,它包含服务器对HTTP请求的响应。
apparent_encoding
明显的编码,由chardet库提供。
close()
用于释放连接。一旦调用此方法,就不能再次访问基础raw
对象。注意:一般不该该显式调用它。
content
响应的内容,以字节为单位。
cookies= None
服务器发回的一堆cookie。
elapsed= None
发送请求到响应到达之间的时间间隔(使用 timedelta 对象表示)。此属性专门度量从发送请求的第一个字节到完成对报头的解析所花费的时间。所以,它不受响应内容或 stream
关键字参数值的影响。
encoding= None
访问 r.text 时解码操做要用到的编码方式。
headers= None
不区分大小写的响应头字典。
例如,headers['content-encoding']
将会返回响应头中键为 Content-Encoding
的键值。
history= None
请求历史记录中的响应
对象列表。任何重定向响应都将在这里结束。该列表从最先的请求到最近的请求进行排序。
is_permanent_redirect
若是此响应是重定向的永久版本之一,则返回 True,不然返回 False。
is_redirect
若是此响应是能够自动处理的格式良好的HTTP重定向(经过 session.resolve_reredirect()
判断),则返回True,不然返回 False。
iter_content(chunk_size=1, decode_unicode=False)
迭代响应数据。当对请求设置stream=True时,这能够避免当即将内容读入内存以得到较大的响应。数据块大小是应该读入内存的字节数。这不必定是解码时返回的每一个项的长度。
chunk_size的类型必须是int或None。None的值将根据流的值发挥不一样的功能。
stream=True将在到达数据块时读取数据,不管块的大小如何。
若是stream=False,则以单个块的形式返回数据。
若是decode_unicode为True,那么将使用基于响应的最佳可用编码对内容进行解码。
iter_lines(chunk_size=512, decode_unicode=False, delimiter=None)
迭代响应数据,一次一行。当对请求设置stream=True时,这能够避免当即将内容读入内存以得到较大的响应。注意
:这种方法是不安全的。
json(**kwargs)
返回响应的 json 编码内容(若是有的话)。
**kwargs-- 表示要传给jason.loads
函数的可选参数。
ValueError --若是响应的主体中不包含有效的 json 数据,则将引起 ValueError 异常。
links
返回已解析的响应头连接(若是有的话)。
next
返回一个PreparedRequest 对象,用于表示重定向链中的下一个请求(若是有的话)。
ok
若是 status_code
小于400,返回 True;若是不小于400,返回 False。
此属性检查响应的状态代码是否在400到600之间,以查看是否存在客户端错误或服务器错误。若是状态码在200到400之间,则返回 True ,而不是检查响应代码是否为 200 OK
。
raise_for_status()
若是发生HTTPError,则引起存储的HTTPError
。
reason= None
响应HTTP状态的文本缘由.
例如:“Not Found” 或者 “OK”.
request= None
这是响应的PreparedRequest
对象。
status_code= None
响应的HTTP状态的整数代码。
例如404或200。
text
使用Unicode字符表示的响应的内容。
若是 Response.encoding 是 None,则使用 chardet
猜想编码。
响应内容的编码按照 RFC 2616 的规定,由 HTTP headers 惟一肯定。若是能够利用非 HTTP 知识更好地猜想编码,应该在访问该特性以前为r.encoding
设置合适的值。
url= None
响应的最终URL位置。
ResponseContextManager类
class ResponseContextManager(response)
能够充当上下文管理器的 Response 类,提供手动控制HTTP 请求在在 Locost 的统计数据中应该标记为成功仍是失败的能力。
这个类是 Response
类的子类。包含两个额外的方法:success
和 failure
。
failure(exc)
将响应报告为失败。
其中参数 exc 能够是一个Python的异常类或者一个字符串。若是是一个字符串,那么将使用这个字符串来实例化 CatchResponseError 类。
例如:
1with self.client.get("/", catch_response=True) as response:
2 if response.content == b"":
3 response.failure("No data")
success()
报告响应成功
例如:
1with self.client.get("/does/not/exist", catch_response=True) as response:
2 if response.status_code == 404:
3 response.success()
InterruptTaskSet异常
exception InterruptTaskSet(reschedule=True)
在 Locust 任务内抛出这个异常时,将会中断这个 Locust 正在执行的当前任务。
事件钩子
事件钩子都是 locust.events.EventHook 类的实例。
class EventHook
简单事件类,用于为 locust 中不一样类型的事件提供钩子。
下面的代码演示如何使用这个类:
1my_event = EventHook()
2def on_my_event(a, b, **kw):
3 print "Event was fired with arguments: %s, %s" % (a, b)
4my_event += on_my_event
5my_event.fire(a="foo", b="bar")
若是 reverse 的值为 True,则处理程序将按照插入时的相反顺序运行。
注意:
强烈建议你在事件监听器中添加通配符关键字参数,以防止在之后的版本中添加新参数时代码中断。
可用的钩子
下面的事件钩子在 locust.events 模块下可用:
request_success= <locust.events.EventHook object>
当一个请求成功完成时触发。
监听者应该使用以下参数:
request_type:使用的请求方法。
name:被调用的URL的路径(若是在对客户端的调用中使用了名称,则重写名称)。
response_time:使用毫秒表示的响应时间。
response_length:响应的 Content-Length 值。
request_failure= <locust.events.EventHook object>
当一个请求失败时触发。
事件触发式将使用以下参数:
request_type:使用的请求方法。
name:被调用的URL的路径(若是在对客户端的调用中使用了名称,则重写名称)。
response_time:用毫秒表示的从发出请求到抛出异常时的时间间隔。
exception:抛出的异常的实例。
locust_error= <locust.events.EventHook object>
当 Locust 类的执行过程当中出现异常时触发。
事件触发式将使用以下参数:
locust_instance:异常发生时的 Locust 类的实例。
exception:抛出的异常。
tb:回溯对象(从 sys.exc_info()[2] 获得)
report_to_master= <locust.events.EventHook object>
当 Locust 在 -slave 模式下运行时使用。用于将数据附加到按期发送给主服务器的数据字典上。当报告要发送到主服务器时,它会按期触发。
注意:
Locust 使用的键 ‘stats’ 和 ‘errors’ 不该该被覆盖。
事件触发式将使用以下参数:
client_id:正在运行的 Locust 进程的客户端 ID。
data:可修改的数据字典,以便附加应发送到主服务器的数据。
slave_report= <locust.events.EventHook object>
当 locust 在 -master 模式下运行使用。并在 Locust 主服务器从从属服务器收到报告时触发。
此事件可用于聚合来自 Locust 从属服务器的数据。
事件触发式将使用以下参数:
client_id:报告 Locust 从属服务器的客户端 ID。
data:来自从属节点的数据字典。
hatch_complete= <locust.events.EventHook object>
当全部 locust 用户都已经生成时触发。
事件触发式将使用以下参数:
user_count:孵化出的用户数量。
quitting= <locust.events.EventHook object>
在退出 locust 进程时触发。
第三方工具
支持其余采样器协议,报告等。
Locust 插件:https://github.com/SvenskaSpel/locust-plugins/
无需手动步骤便可自动执行分布式运行
Locust集群:https://github.com/SvenskaSpel/locust-swarm/(蝗虫群)
使用其余语言
Locust主服务器和Locust从服务器经过交换msgpack消息进行通讯,这是许多语言所支持的。所以,您可使用任何喜欢的语言编写Locust任务。为了方便起见,一些库充当了从属运行程序。他们运行你的Locust任务,并按期向master报告。
Golang
Boomer:https://github.com/myzhan/boomer/
Java
Locust4j:https://github.com/myzhan/locust4j
Swarm: https://github.com/anhldbk/swarm
配置管理
部署Locust很容易,可是有些工具仍然能够提供必定程度的便利。
tinx.locust是Ansible的一个安装角色,用于配置和控制Locust系统服务,或使用ansible-container构建Locust docker映像。还管理locustfile和相应的测试数据。
文章合集
Selenium | Appium | Jenkins | Jmeter
软件测试方法汇总 | Postman接口参数化 | 测试用例设计
免费福利 视频教程
Selenium | Appium | Jenkins | Jmeter
往期性能推文:
03|性能综述: 怎么理解TPS、QPS、RT、吞吐量这些性能指标?
04|JMeter和LoadRunner:要知道工具仅仅只是工具
万水千山老是情,点个“在看” 行不行!!?
本文分享自微信公众号 - 软测小生(ruancexiaosheng)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。