在《【LocustPlus序】漫谈服务端性能测试》中,我对服务端性能测试的基础概念和性能测试工具的基本原理进行了介绍,而且重点推荐了Locust
这一款开源性能测试工具。然而,当前在网络上针对Locust
的教程极少,无论是中文仍是英文,基本都是介绍安装方法和简单的测试案例演示,但对于较复杂测试场景的案例演示却基本没有,所以不少测试人员都感受难以将Locust
应用到实际的性能测试工做当中。html
通过一段时间的摸索,包括通读Locust
官方文档和项目源码,而且在多个性能测试项目中对Locust
进行应用实践,事实证实,Locust
彻底能知足平常的性能测试需求,LoadRunner
能实现的功能Locust
也基本都能实现。python
本文将从Locust
的功能特性出发,结合实例对Locust
的使用方法进行介绍。考虑到大众广泛对LoadRunner
比较熟悉,在讲解Locust
时也会采用LoadRunner
的一些概念进行类比。git
先从Locust
的名字提及。Locust
的原意是蝗虫,原做者之因此选择这个名字,估计也是听过这么一句俗语,“蝗虫过境,寸草不生”。我在网上找了张图片,你们能够感觉下。github
而Locust
工具生成的并发请求就跟一大群蝗虫通常,对咱们的被测系统发起攻击,以此检测系统在高并发压力下是否能正常运转。web
在《【LocustPlus序】漫谈服务端性能测试》中说过,服务端性能测试工具最核心的部分是压力发生器,而压力发生器的核心要点有两个,一是真实模拟用户操做,二是模拟有效并发。算法
在Locust
测试框架中,测试场景是采用纯Python脚本进行描述的。对于最多见的HTTP(S)
协议的系统,Locust
采用Python的requests
库做为客户端,使得脚本编写大大简化,富有表现力的同时且极具美感。而对于其它协议类型的系统,Locust
也提供了接口,只要咱们能采用Python编写对应的请求客户端,就能方便地采用Locust
实现压力测试。从这个角度来讲,Locust
能够用于压测任意类型的系统。微信
在模拟有效并发方面,Locust
的优点在于其摒弃了进程和线程,彻底基于事件驱动,使用gevent
提供的非阻塞IO
和coroutine
来实现网络层的并发请求,所以即便是单台压力机也能产生数千并发请求数;再加上对分布式运行的支持,理论上来讲,Locust
能在使用较少压力机的前提下支持极高并发数的测试。网络
编写Locust
脚本,是使用Locust
的第一步,也是最为重要的一步。session
先来看一个最简单的示例。数据结构
from locust import HttpLocust, TaskSet, task
class WebsiteTasks(TaskSet):
def on_start(self):
self.client.post("/login", {
"username": "test",
"password": "123456"
})
@task(2)
def index(self):
self.client.get("/")
@task(1)
def about(self):
self.client.get("/about/")
class WebsiteUser(HttpLocust):
task_set = WebsiteTasks
host = "http://debugtalk.com"
min_wait = 1000
max_wait = 5000复制代码
在这个示例中,定义了针对http://debugtalk.com
网站的测试场景:先模拟用户登陆系统,而后随机地访问首页(/
)和关于页面(/about/
),请求比例为2:1
;而且,在测试过程当中,两次请求的间隔时间为1~5
秒间的随机值。
那么,如上Python脚本是如何表达出以上测试场景的呢?
从脚本中能够看出,脚本主要包含两个类,一个是WebsiteUser
(继承自HttpLocust
,而HttpLocust
继承自Locust
),另外一个是WebsiteTasks
(继承自TaskSet
)。事实上,在Locust
的测试脚本中,全部业务测试场景都是在Locust
和TaskSet
两个类的继承子类中进行描述的。
那如何理解Locust
和TaskSet
这两个类呢?
简单地说,Locust类
就比如是一群蝗虫,而每一只蝗虫就是一个类的实例。相应的,TaskSet类
就比如是蝗虫的大脑,控制着蝗虫的具体行为,即实际业务场景测试对应的任务集。
这个比喻可能不是很准确,接下来,我将分别对Locust
和TaskSet
两个类进行详细介绍。
在Locust类
中,具备一个client
属性,它对应着虚拟用户做为客户端所具有的请求能力,也就是咱们常说的请求方法。一般状况下,咱们不会直接使用Locust
类,由于其client
属性没有绑定任何方法。所以在使用Locust
时,须要先继承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 import TaskSet, task
class UserBehavior(TaskSet):
@task(1)
def test_job1(self):
self.client.get('/job1')
@task(2)
def test_job2(self):
self.client.get('/job2')复制代码
采用tasks属性
定义任务信息时,描述形式以下:
from locust import TaskSet
def test_job1(obj):
obj.client.get('/job1')
def test_job2(obj):
obj.client.get('/job2')
class UserBehavior(TaskSet):
tasks = {test_job1:1, test_job2:2}
# tasks = [(test_job1,1), (test_job1,2)] # 两种方式等价复制代码
在如上两种定义任务信息的方式中,均设置了权重属性,即执行test_job2
的频率是test_job1
的两倍。
若不指定执行任务的权重,则至关于比例为1:1
。
from locust import TaskSet, task
class UserBehavior(TaskSet):
@task
def test_job1(self):
self.client.get('/job1')
@task
def test_job2(self):
self.client.get('/job2')复制代码
from locust import TaskSet
def test_job1(obj):
obj.client.get('/job1')
def test_job2(obj):
obj.client.get('/job2')
class UserBehavior(TaskSet):
tasks = [test_job1, test_job2]
# tasks = {test_job1:1, test_job2:1} # 两种方式等价复制代码
在TaskSet
子类中除了定义任务信息,还有一个是常常用到的,那就是on_start
函数。这个和LoadRunner
中的vuser_init
功能相同,在正式执行测试前执行一次,主要用于完成一些初始化的工做。例如,当测试某个搜索功能,而该搜索功能又要求必须为登陆态的时候,就能够先在on_start
中进行登陆操做;前面也提到,HttpLocust
使用到了requests.Session
,所以后续全部任务执行过程当中就都具备登陆态了。
掌握了HttpLocust
和TaskSet
,咱们就基本具有了编写测试脚本的能力。此时再回过头来看前面的案例,相信你们都能很好的理解了。
然而,当面对较复杂的测试场景,可能有的同窗仍是会感受无从下手;例如,不少时候脚本须要作关联或参数化处理,这些在LoadRunner
中集成的功能,换到Locust
中就不知道怎么实现了。可能也是这方面的缘由,形成不少测试人员都感受难以将Locust应用到实际的性能测试工做当中。
其实这也跟Locust
的目标定位有关,Locust
的定位就是small and very hackable
。可是小巧并不意味着功能弱,咱们彻底能够经过Python脚本自己来实现各类各样的功能,若是你们有疑问,咱们不妨逐项分解来看。
在LoadRunner
这款功能全面应用普遍的商业性能测试工具中,脚本加强无非就涉及到四个方面:
先说关联这一项。在某些请求中,须要携带以前从Server端返回的参数,所以在构造请求时须要先从以前请求的Response中提取出所需的参数,常见场景就是session_id
。针对这种状况,LoadRunner
虽然可能经过录制脚本进行自动关联,可是效果并不理想,在实际测试过程当中也基本都是靠测试人员手动的来进行关联处理。
在LoadRunner
中手动进行关联处理时,主要是经过使用注册型函数,例如web_reg_save_param
,对前一个请求的响应结果进行解析,根据左右边界或其它特征定位到参数值并将其保存到参数变量,而后在后续请求中使用该参数。采用一样的思想,咱们在Locust
脚本中也彻底能够实现一样的功能,毕竟只是Python脚本,经过官方库函数re.search
就能实现全部需求。甚至针对html页面,咱们也能够采用lxml
库,经过etree.HTML(html).xpath
来更优雅地实现元素定位。
而后再来看参数化这一项。这一项极其广泛,主要是用在测试数据方面。但经过概括,发现其实也能够归纳为三种类型。
经过以上概括,能够确信地说,以上三种类型基本上能够覆盖咱们平常性能测试工做中的全部参数化场景。
在LoadRunner
中是有一个集成的参数化模块,能够直接配置参数化策略。那在Locust
要怎样实现该需求呢?
答案依旧很简单,使用Python的list
和queue
数据结构便可!具体作法是,在WebsiteUser
定义一个数据集,而后全部虚拟用户在WebsiteTasks
中就能够共享该数据集了。若是不要求数据惟一性,数据集选择list
数据结构,从头至尾循环遍历便可;若是要求数据惟一性,数据集选择queue
数据结构,取数据时进行queue.get()
操做便可,而且这也不会循环取数据;至于涉及到须要循环取数据的状况,那也简单,每次取完数据后再将数据插入到队尾便可,queue.put_nowait(data)
。
最后再说下检查点。该功能在LoadRunner
中一般是使用web_reg_find
这类注册函数进行检查的。在Locust
脚本中,处理就更方便了,只须要对响应的内容关键字进行assert xxx in response
操做便可。
针对如上各类脚本加强的场景,我也经过代码示例分别进行了演示。但考虑到文章中插入太多代码会影响到阅读,所以将代码示例部分剥离了出来,若有须要请点击查看《深刻浅出开源性能测试工具Locust(脚本加强)》。
欢迎关注个人我的博客和微信公众号。
DebugTalk