一、 Locust前言
在Locust测试框架中,测试场景是采用纯Python脚本进行描述的。对于最常见的HTTP(S)协议的系统,Locust采用Python的requests库作为客户端,使得脚本编写大大简化,富有表现力的同时且极具美感。而对于其它协议类型的系统,Locust也提供了接口,只要我们能采用Python编写对应的请求客户端,就能方便地采用Locust实现压力测试。从这个角度来说,Locust可以用于压测任意类型的系统。
在模拟有效并发方面,Locust的优势在于其放弃了进程和线程,完全基于事件驱动,使用gevent提供的非阻塞IO和coroutine来实现网络层的并发请求,因此即使是单台压力机也能产生数千并发请求数;再加上对分布式运行的支持,理论上来说,Locust能在使用较少压力机的前提下支持极高并发数的测试。
二、 Locust部署
1、安装Python
Linux 升级 Python 至 3.x参照如下文章
http://blog.youkuaiyun.com/liang19890820/article/details/51079633
2、安装pip
sudo easy_install pip
3、 安装Homebrew
参照网址:https://brew.sh/
4、 安装依赖包libev
brew install libev
5、 安装 pyzmq
如果你打算运行Locust 分布在多个进程/机器,我们建议你也安装pyzmq.
pip install pyzmq
6、安装locustio
pip install locustio
验证是否安装成功
locust--help
三、 Locust使用
1、 参数化
1)循环取数据,数据可重复使用
所有并发虚拟用户共享同一份测试数据,各虚拟用户在数据列表中循环取值。
例如,模拟5用户并发请求网页,总共有100个URL地址,每个虚拟用户都会依次循环加载这100个URL地址;加载示例如下表所示。
代码示例;
from locust import TaskSet, task, HttpLocust #循环取数据,数据可重复使用 class UserBehavior(TaskSet): def on_start(self): self.index = 0 pass @task def test_visit(self): data = self.locust.share_data[self.index] self.index = (self.index + 1) % len(self.locust.share_data) print('数据 user_id: {}, order_id: {}' \ .format(data['user_id'], data['order_id'])) payload = { 'user_id': data['user_id'], 'order_id': data['order_id'], 'channel': "beike", 'type': "credit" } self.client.post('/risk/applyInfo', data=payload) class WebsiteUser(HttpLocust): host = 'http://10.106.124.81:8080' task_set = UserBehavior share_data = [] user_id = 40000000001 order_id = 450000001 for index in range(0, 100): data = { "user_id": "%d" % user_id, "order_id": "%d" % order_id, } user_id += 1 share_data.append(data) min_wait = 1000 max_wait = 1000
2)保证并发测试数据唯一性,不循环取数据
所有并发虚拟用户共享同一份测试数据,并且保证虚拟用户使用的数据不重复。
例如模拟5用户并发请求网页,总共有100个URL地址,要求每个请求地址不重复,直到100个URL请求完毕后结束;加载示例如下表所示。
代码示例;
t data = self.locust.user_data_queue.get() except queue.Empty: print('运行用户已跑完') exit(0) print('数据 user_id: {}, order_id: {}'\ .format(data['user_id'], data['order_id'])) payload = { 'user_id': data['user_id'], 'order_id': data['order_id'], 'channel': "beike", 'type': "credit" } self.client.post('/risk/applyInfo', data=payload) class WebsiteUser(HttpLocust): host = 'http://10.106.124.81:8080' task_set = UserDatasource user_data_queue = queue.Queue() user_id = 40000000001 order_id = 450000001 for index in range(0,100): data = { "user_id": "%d" % user_id, "order_id": "%d" % order_id, } user_id += 1 order_id += 1 user_data_queue.put_nowait(data) min_wait = 1000 max_wait = 1000
3)保证并发测试数据唯一性,可循环取数据
所有并发虚拟用户共享同一份测试数据,并且保证虚拟用户使用的数据不重复。
例如模拟5用户并发请求网页,总共有100个URL地址,要求每个请求地址不重复,但是可循环使用数据;加载示例如下表所示。
代码示例;
from locust import TaskSet, task, HttpLocust import queue #保证并发测试数据唯一性,循环取数据 #该种场景的实现方式与上一种场景基本相同,唯一的差异在于,每次使用完数据后,需要再将数据放入队列中 # http://10.106.124.81:8080/risk/applyInfo?user_id=40000050001&channel=beike&order_id=450050001&type=credit class UserDatasource(TaskSet): @task def test_applyInfo(self): try: data = self.locust.user_data_queue.get() except queue.Empty: print('运行用户已跑完') exit(0) print('数据 user_id: {}, order_id: {}'\ .format(data['user_id'], data['order_id'])) payload = { 'user_id': data['user_id'], 'order_id': data['order_id'], 'channel': "beike", 'type': "credit" } self.client.post('/risk/applyInfo', data=payload) self.locust.user_data_queue.put_nowait(data) class WebsiteUser(HttpLocust): host = 'http://10.106.124.81:8080' task_set = UserDatasource user_data_queue = queue.Queue() user_id = 40000000001 order_id = 450000001 for index in range(0,50): data = { "user_id": "%d" % user_id, "order_id": "%d" % order_id, } user_id += 1 order_id += 1 user_data_queue.put_nowait(data) min_wait = 1000 max_wait = 1000
1、关联与检查点
代码示例
from locust import HttpLocust, TaskSet, task import re class WebsiteTasks(TaskSet): def on_start(self): userinfo = { 'nickname': '15811539615', 'password': '4297F44B13955235245B2497399D7A93', 'loanCommentCode': "" } with self.client.post("login/userlogin.shtml", catch_response=True,verify=False,data=userinfo) as response: html = response.text url = response.url print('url前缀%s' % url) self.validatelogin(html, response) @staticmethod #验证登录成功 def validatelogin(html, response): result = re.search('message":".*?(\w+).*?","success', html) print('响应字符串:%s' % html) print('检查返回比对的字符串:%s'%result.group(1)) if result.group(1) == '登陆成功': print('登录验证成功!') else: print('登录失败!') response.failure('登录失败') @staticmethod #验证我的账户跳转成功 def validateaccount(html, response): result = re.search('class="text-info">.*?(\w+).*?</a><i class', html) # print('响应字符串:%s' % html) print('检查返回比对的字符串:%s' % result.group(1)) if result.group(1) == 'lc303038910': print('我的账户跳转成功!') else: print('我的账户跳转失败!') response.failure('我的账户跳转失败') @task def useraccount(self): with self.client.post("usercenter/accountcenter.shtml", catch_response=True,verify=False) as response: html = response.text url = response.url print('url前缀%s' % url) self.validateaccount(html,response) class WebsiteUser(HttpLocust): task_set = WebsiteTasks host = "https://www.caifuxq.com/" min_wait = 1000 max_wait = 1000
四、 Locust运行模式
在开始运行Locust脚本之前,我们先来看下Locust支持的运行模式。
运行Locust时,通常会使用到两种运行模式:单进程运行和多进程分布式运行。
单进程运行模式的意思是,Locust所有的虚拟并发用户均运行在单个Python进程中,具体从使用形式上,又分为no_web和web两种形式。该种模式由于单进程的原因,并不能完全发挥压力机所有处理器的能力,因此主要用于调试脚本和小并发压测的情况。
当并发压力要求较高时,就需要用到Locust的多进程分布式运行模式。从字面意思上看,大家可能第一反应就是多台压力机同时运行,每台压力机分担负载一部分的压力生成。的确,Locust支持任意多台压力机(一主多从)的分布式运行模式,但这里说到的多进程分布式运行模式还有另外一种情况,就是在同一台压力机上开启多个slave的情况。这是因为当前阶段大多数计算机的CPU都是多处理器(multipleprocessor cores),单进程运行模式下只能用到一个处理器的能力,而通过在一台压力机上运行多个slave,就能调用多个处理器的能力了。比较好的做法是,如果一台压力机有N个处理器内核,那么就在这台压力机上启动一个master,N个slave。当然,我们也可以启动N的倍数个slave,但是根据我的试验数据,效果跟N个差不多,因此只需要启动N个slave即可。
1、 单进程运行
no_web(表示不使用web界面)
Locust是通过在Terminal中执行命令进行启动的,通用的参数有如下两个:
-H, --host:被测系统的host,若在Terminal中不进行指定,就需要在Locust子类中通过host参数进行指定;
-f, --locustfile:指定执行的Locust脚本文件;
如果采用no_web形式,则需使用--no-web参数,并会用到如下几个参数。
-c, --clients:指定并发用户数;
-n, --num-request:指定总执行测试;
-r, --hatch-rate:指定并发加压速率,默认值位1。
-t, 设置设置运行时间
终端命令
web
如果采用web形式,则通常情况下无需指定其它额外参数,Locust默认采用8089端口启动web;如果要使用其它端口,就可以使用如下参数进行指定。
-P, --port:指定web端口,默认为8089.
此时,Locust并没有开始执行测试,还需要在Web页面中配置参数后进行启动。
如果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参数。
--no-reset-stats 就能统计全部数据了
参数配置完毕后,点击【Startswarming】即可开始测试。
1、 多进程分布式运行
不管是单机多进程,还是多机负载模式,运行方式都是一样的,都是先运行一个master,再启动多个slave。启动master时,需要使用--master参数;同样的,如果要使用8089以外的端口,还需要使用-P,--port参数。
locust -f test4.py --no-reset-stats--master
master启动后,还需要启动slave才能执行测试任务。
启动slave时需要使用--slave参数;在slave中,就不需要再指定端口了。
locust -f test4.py --no-reset-stats --slave
如果slave与master不在同一台机器上,还需要通过--master-host参数再指定master的IP地址。
locust -f test4.py --no-reset-stats --slave--master-host=10.106.29.235
五、Locust场景控制
1、设置并发数
通过代码中min_wait max_wait设置请求之间的间隔时间
两个值设置一样代表请求之间的间隔时间固定
以下以无界面方式运行脚本c
locust -ftest4.py --no-web -c 2 -n 10
例min_wait max_wait分别设置1(间隔1s) -c设置2 -n设置10
场景:每秒并发2 共执行10条记录