性能测试工具Locust的使用

1、写在前面html

官网: https://www.locust.io/node

官方使用文档:https://docs.locust.io/en/latest/python

大并发量测试时,建议在linux系统下进行。linux

 

2、Locust安装nginx

1.一、   --->  pip3 install locust 
git

1.2 、 经过GitHub上克隆项目安装(Python3推荐):https://github.com/locustio/locust  ,而后执行     ...\locust> python setup.py install
github

 二、安装 pyzmqgolang

 If you intend to run Locust distributed across multiple processes/machines, we recommend you to also install pyzmq.web

 若是打算运行Locust 分布在多个进程/机器,须要安装pyzmq.算法

 经过pip命令安装。 />  pip install pyzmq

三、安装成功,CMD敲入命令验证。 /> locust --help

Options: -h, --help            show this help message and exit -H HOST, --host=HOST Host to load test in the following format: http://10.21.32.33
  --web-host=WEB_HOST   Host to bind the web interface to. Defaults to '' (all interfaces) -P PORT, --port=PORT, --web-port=PORT Port on which to run web host -f LOCUSTFILE, --locustfile=LOCUSTFILE Python module file to import, e.g. '../other.py'. Default: locustfile --master              Set locust to run in distributed mode with this process as master --slave               Set locust to run in distributed mode with this process as slave --master-host=MASTER_HOST Host or IP address of locust master for distributed load testing. Only used when running with --slave. Defaults to 127.0.0.1. --master-port=MASTER_PORT The port to connect to that is used by the locust master for distributed load testing. Only used when running with --slave. Defaults to 5557. Note that slaves will also connect to the master node on this port + 1. --master-bind-host=MASTER_BIND_HOST Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --no-web              Disable the web interface, and instead start running the test immediately. Requires -c and -r to be specified. -c NUM_CLIENTS, --clients=NUM_CLIENTS Number of concurrent clients. Only used together with --no-web -r HATCH_RATE, --hatch-rate=HATCH_RATE The rate per second in which clients are spawned. Only used together with --no-web -n NUM_REQUESTS, --num-request=NUM_REQUESTS Number of requests to perform. Only used together with --no-web -L LOGLEVEL, --loglevel=LOGLEVEL Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO. --logfile=LOGFILE Path to log file. If not set, log will go to stdout/stderr --print-stats Print stats in the console --only-summary Only print the summary stats -l, --list Show list of possible locust classes and exit --show-task-ratio     print table of the locust classes' task execution
 ratio --show-task-ratio-json print json data of the locust classes' task execution
 ratio -V, --version         show program's version number and exit

参数说明:

-h, --help 查看帮助 -H HOST, --host=HOST    指定被测试的主机,采用以格式:http://10.21.32.33
--web-host=WEB_HOST    指定运行 Locust Web 页面的主机,默认为空 ''-P PORT, --port=PORT, --web-port=PORT    指定 --web-host 的端口,默认是8089 -f LOCUSTFILE, --locustfile=LOCUSTFILE 指定运行 Locust 性能测试文件,默认为: locustfile.py --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE 以CSV格式存储当前请求测试数据。 --master Locust 分布式模式使用,当前节点为 master 节点。 --slave Locust 分布式模式使用,当前节点为 slave 节点。 --master-host=MASTER_HOST    分布式模式运行,设置 master 节点的主机或 IP 地址,只在与 --slave 节点一块儿运行时使用,默认为:127.0.0.1. --master-port=MASTER_PORT    分布式模式运行, 设置 master 节点的端口号,只在与 --slave 节点一块儿运行时使用,默认为:5557。注意,slave 节点也将链接到这个端口+1 上的 master 节点。 --master-bind-host=MASTER_BIND_HOST    Interfaces (hostname, ip) that locust master should bind to. Only used when running with --master. Defaults to * (all available interfaces). --master-bind-port=MASTER_BIND_PORT    Port that locust master should bind to. Only used when running with --master. Defaults to 5557. Note that Locust will also use this port + 1, so by default the master node will bind to 5557 and 5558. --expect-slaves=EXPECT_SLAVES    How many slaves master should expect to connect before starting the test (only when --no-web used). --no-web    no-web 模式运行测试,须要 -c 和 -r 配合使用. -c NUM_CLIENTS, --clients=NUM_CLIENTS    指定并发用户数,做用于 --no-web 模式。 -r HATCH_RATE, --hatch-rate=HATCH_RATE    指定每秒启动的用户数,做用于 --no-web 模式。 -t RUN_TIME, --run-time=RUN_TIME    设置运行时间, 例如: (300s, 20m, 3h, 1h30m). 做用于 --no-web 模式。 -L LOGLEVEL, --loglevel=LOGLEVEL    选择 log 级别(DEBUG/INFO/WARNING/ERROR/CRITICAL). 默认是 INFO. --logfile=LOGFILE    日志文件路径。若是没有设置,日志将去 stdout/stderr --print-stats 在控制台中打印数据 --only-summary 只打印摘要统计 --no-reset-stats Do not reset statistics once hatching has been completed。 -l, --list    显示测试类, 配置 -f 参数使用 --show-task-ratio    打印 locust 测试类的任务执行比例,配合 -f 参数使用. --show-task-ratio-json    以 json 格式打印 locust 测试类的任务执行比例,配合 -f 参数使用. -V, --version    查看当前 Locust 工具的版本.

 

四、Locust主要由下面的几个库构成:

1) gevent

gevent是一种基于协程的Python网络库,它用到Greenlet提供的,封装了libevent事件循环的高层同步API。

2) flask

Python编写的轻量级Web应用框架。

3) requests

Python Http库

4) msgpack-python

MessagePack是一种快速、紧凑的二进制序列化格式,适用于相似JSON的数据格式。msgpack-python主要提供MessagePack数据序列化及反序列化的方法。

5) six

Python2和3兼容库,用来封装Python2和Python3之间的差别性

6) pyzmq

pyzmq是zeromq(一种通讯队列)的Python绑定,主要用来实现Locust的分布式模式运行

当咱们在安装 Locust 时,它会检测咱们当前的 Python 环境是否已经安装了这些库,若是没有安装,它会先把这些库一一装上。而且对这些库版本有要求,有些是必须等于某版本,有些是大于某版本。咱们也能够事先把这些库所有按要求装好,再安装Locust时就会快上许多。

 

3、编写接口压测脚本文件locustfile.py

 

 1 from locust import HttpLocust, TaskSet, task  2   
 3 class ScriptTasks(TaskSet):  4 def on_start(self):  5 self.client.post("/login", {  6 "username": "test",  7 "password": "123456"
 8 })  9   
10 @task(2) 11 def index(self): 12 self.client.get("/") 13   
14 @task(1) 15 def about(self): 16 self.client.get("/about/") 17  
18 @task(1) 19 def demo(self): 20 payload={} 21 headers={} 22 self.client.post("/demo/",data=payload, headers=headers) 23   
24 class WebsiteUser(HttpLocust): 25 task_set = ScriptTasks 26 host = "http://example.com" 
27 min_wait = 1000
28 max_wait = 5000

脚本解读

1、建立ScriptTasks()类继承TaskSet类:  用于定义测试业务。

二、建立index()、about()、demo()方法分别表示一个行为,访问http://example.com。用@task() 装饰该方法为一个任务。一、2表示一个Locust实例被挑选执行的权重,数值越大,执行频率越高。在当前ScriptTasks()行为下的三个方法得执行比例为2:1:1

3、WebsiteUser()类: 用于定义模拟用户。

4、task_set :  指向一个定义了的用户行为类。

5、host:   指定被测试应用的URL的地址

6、min_wait :   用户执行任务之间等待时间的下界,单位:毫秒。

七、max_wait :   用户执行任务之间等待时间的上界,单位:毫秒。

脚本使用场景解读

在这个示例中,定义了针对http://example.com网站的测试场景:先模拟用户登陆系统,而后随机地访问首页(/)和关于页面(/about/),请求比例为2:1,demo方法主要用来阐述client对post接口的处理方式;而且,在测试过程当中,两次请求的间隔时间为1->5秒间的随机值。

从脚本中能够看出,脚本主要包含两个类,一个是WebsiteUser(继承自HttpLocust,而HttpLocust继承自Locust),另外一个是ScriptTasks(继承自TaskSet)。事实上,在Locust的测试脚本中,全部业务测试场景都是在LocustTaskSet两个类的继承子类中进行描的。

那如何理解LocustTaskSet这两个类呢?简单地说,Locust类就比如是一群蝗虫,而每一只蝗虫就是一个类的实例。相应的,TaskSet类就比如是蝗虫的大脑,控制着蝗虫的具体行为,即实际业务场景测试对应的任务集。

 

4、Locust类

实例脚本

伪代码:

from locust import HttpLocust, TaskSet, task

class WebsiteTasks(TaskSet):
    def on_start(self):   #进行初始化的工做,每一个Locust用户开始作的第一件事
        payload = {
            "username": "test_user",
            "password": "123456",
        }
        header = {
            "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
        }
        self.client.post("/login",data=payload,headers=header)#self.client属性使用Python request库的全部方法,调用和使用方法和requests彻底一致;

    @task(5)    #经过@task()装饰的方法为一个事务,方法的参数用于指定该行为的执行权重,参数越大每次被虚拟用户执行的几率越高,默认为1
    def index(self):
        self.client.get("/")

    @task(1)
    def about(self):
        self.client.get("/about/")

class WebsiteUser(HttpLocust):
    host     = "https://github.com/" #被测系统的host,在终端中启动locust时没有指定--host参数时才会用到
    task_set = WebsiteTasks          #TaskSet类,该类定义用户任务信息,必填。这里就是:WebsiteTasks类名,由于该类继承TaskSet;
    min_wait = 5000  #每一个用户执行两个任务间隔时间的上下限(毫秒),具体数值在上下限中随机取值,若不指定默认间隔时间固定为1秒
    max_wait = 15000

 伪代码中对https://github.com/网站的测试场景,先模拟用户登陆系统,而后随机访问首页/和/about/,请求比例5:1,而且在测试过程当中,两次请求的间隔时间1-5秒的随机值;

    on_start方法,在正式执行测试前执行一次,主要用于完成一些初始化的工做,例如登陆操做;

WebsiteTasks类中如何去调用 WebsiteUser(HttpLocust)类中定义的字段和方法呢?

 经过在WebsiteTasks类中self.locust.xxoo      xxoo就是咱们在WebsiteUser类中定义的字段或方法;

伪代码:

from locust import HttpLocust, TaskSet, task
import hashlib
import queue
 
class WebsiteTasks(TaskSet):
 
    @task(5)
    def index(self):
        data = self.locust.user_data_queue  #获取WebsiteUser里面定义的ser_data_queue队列
        md5_data=self.locust.md5_encryption() #获取WebsiteUser里面定义的md5_encryption()方法
        self.client.get("/")
 
class WebsiteUser(HttpLocust):
    host     = "https://github.com/"
    task_set = WebsiteTasks
    min_wait = 5000
    max_wait = 15000
    user_data_queue = queue.Queue()
 
    def md5_encryption(self,star):
        '''md5加密方法'''
        obj    = hashlib.md5()
        obj.update(bytes(star,encoding="utf-8"))
        result = obj.hexdigest()
        return result

伪代码中测试场景如何表达?

代码主要包含两个类:

  1. WebsiteUser继承(HttpLocust,而HttpLocust继承自Locust)
  2. WebsiteTasks继承(TaskSet)

在Locust测试脚本中,全部业务测试场景都是在Locust和TaskSet两个类的继承子类中进行描述;

简单说:Locust类就相似一群蝗虫,而每只蝗虫就是一个类的实例。TaskSet类就相似蝗虫的大脑,控制蝗虫的具体行为,即实际业务场景测试对应的任务集;

源码中:class Locust(object)和class HttpLocust(Locust)

 1 class Locust(object):
 2     """
 3     Represents a "user" which is to be hatched and attack the system that is to be load tested.
 4      
 5     The behaviour of this user is defined by the task_set attribute, which should point to a
 6     :py:class:`TaskSet <locust.core.TaskSet>` class.
 7      
 8     This class should usually be subclassed by a class that defines some kind of client. For
 9     example when load testing an HTTP system, you probably want to use the
10     :py:class:`HttpLocust <locust.core.HttpLocust>` class.
11     """
12      
13     host = None
14     """Base hostname to swarm. i.e: http://127.0.0.1:1234"""
15      
16     min_wait = 1000
17     """Minimum waiting time between the execution of locust tasks"""
18      
19     max_wait = 1000
20     """Maximum waiting time between the execution of locust tasks"""
21      
22     task_set = None
23     """TaskSet class that defines the execution behaviour of this locust"""
24      
25     stop_timeout = None
26     """Number of seconds after which the Locust will die. If None it won't timeout."""
27  
28     weight = 10
29     """Probability of locust being chosen. The higher the weight, the greater is the chance of it being chosen."""
30          
31     client = NoClientWarningRaiser()
32     _catch_exceptions = True
33      
34     def __init__(self):
35         super(Locust, self).__init__()
36      
37     def run(self):
38         try:
39             self.task_set(self).run()
40         except StopLocust:
41             pass
42         except (RescheduleTask, RescheduleTaskImmediately) as e:
43  
44 class HttpLocust(Locust):
45     """
46     Represents an HTTP "user" which is to be hatched and attack the system that is to be load tested.
47      
48     The behaviour of this user is defined by the task_set attribute, which should point to a
49     :py:class:`TaskSet <locust.core.TaskSet>` class.
50      
51     This class creates a *client* attribute on instantiation which is an HTTP client with support
52     for keeping a user session between requests.
53     """
54      
55     client = None
56     """
57     Instance of HttpSession that is created upon instantiation of Locust.
58     The client support cookies, and therefore keeps the session between HTTP requests.
59     """
60     def __init__(self):
61            super(HttpLocust, self).__init__()
62            if self.host is None:
63                raise LocustError("You must specify the base host. Either in the host attribute in the Locust class, or on the command line using the --host option.")
64       self.client = HttpSession(base_url=self.host)

 在Locust类中,静态字段client即客户端的请求方法,这里的client字段没有绑定客户端请求方法,所以在使用Locust时,须要先继承Locust类class HttpLocust(Locust),而后在self.client =HttpSession(base_url=self.host)绑定客户端请求方法;

   对于常见的HTTP(s)协议,Locust已经实现了HttpLocust类,其self.client=HttpSession(base_url=self.host),而HttpSession继承自requests.Session。所以在测试HTTP(s)的Locust脚本中,能够经过client属性来使用Python requests库的所 有方法,调用方式与      reqeusts彻底一致。另外,因为requests.Session的使用,client的方法调用之间就自动具备了状态记忆功能。常见的场景就是,在登陆系统后能够维持登陆状态的Session,从然后续HTTP请求操做都能带上登陆状态;

Locust类中,除了client属性,还有几个属性须要关注:

  • task_set ---> 指向一个TaskSet类,TaskSet类定义了用户的任务信息,该静态字段为必填;
  • max_wait/min_wait ---> 每一个用户执行两个任务间隔的上下限(毫秒),具体数值在上下限中随机取值,若不指定则默认间隔时间为1秒;
  • host    --->被测试系统的host,当在终端中启动locust时没有指定--host参数时才会用到;
  • weight--->同时运行多个Locust类时,用于控制不一样类型的任务执行权重;

Locust流程,测试开始后,每一个虚拟用户(Locust实例)运行逻辑都会遵照以下规律:

  1. 先执行WebsiteTasks中的on_start(只执行一次),做为初始化;
  2. 从WebsiteTasks中随机挑选(若是定义了任务间的权重关系,那么就按照权重关系随机挑选)一个任务执行;
  3. 根据Locust类中min_wait和max_wait定义的间隔时间范围(若是TaskSet类中也定义了min_wait或者max_wait,以TaskSet中的优先),在时间范围中随机取一个值,休眠等待;
  4. 重复2~3步骤,直到测试任务终止;

class TaskSet

       TaskSet类实现了虚拟用户所执行任务的调度算法,包括规划任务执行顺序(schedule_task)、挑选下一个任务(execute_next_task)、执行任务(execute_task)、休眠等待(wait)、中断控制(interrupt)等待。在此基础上,就能够在TaskSet子类中采用很是简洁的方式来描述虚拟用户的业务测试场景,对虚拟用户的全部行为进行组织和描述,并能够对不一样任务的权重进行配置。

@task

    经过@task()装饰的方法为一个事务。方法的参数用于指定该行为的执行权重。参数越大每次被虚拟用户执行的几率越高。若是不设置默认为1。

    TaskSet子类中定义任务信息时,采起两种方式:@task装饰器和tasks属性。

采用@task装饰器定义任务信息时:

from locust import TaskSet, task

class UserBehavior(TaskSet):
    @task(1)
    def test_job1(self):
        self.client.get('/test1')

    @task(3)
    def test_job2(self):
        self.client.get('/test2')

采用tasks属性定义任务信息时

from locust import TaskSet

def test_job1(obj):
    obj.client.get('/test1')

def test_job2(obj):
    obj.client.get('/test2')

class UserBehavior(TaskSet):
    tasks = {test_job1:1, test_job2:3}
    # tasks = [(test_job1,1), (test_job1,3)] # 两种方式等价

上面两种定义任务信息方式中,均设置了权重属性,即执行test_job2的频率是test_job1的两倍。

若不指定,默认比例为1:1。

 

高级用法:

关联

在某些请求中,须要携带以前response中提取的参数,常见场景就是session_id。Python中可用经过re正则匹配,对于返回的html页面,可用采用lxml库来定位获取须要的参数;

from locust import HttpLocust, TaskSet, task
from lxml import etree

class WebsiteTasks(TaskSet):

    def get_session(self,html): #关联例子
        tages = etree.HTML(html)
        return tages.xpath("//div[@class='btnbox']/input[@name='session']/@value")[0]

    def on_start(self):
        html = self.client.get('/index')
        session = self.get_session(html.text)
        payload = {
            "username": "test_user",
            "password": "123456",
            'session' : session
        }
        header = {
            "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
        }
        self.client.post("/login",data=payload,headers=header)

    @task(5)
    def index(self):
        self.client.get("/")
        assert response['ErrorCode']==0   #断言

    @task(1)
    def about(self):
        self.client.get("/about/")

class WebsiteUser(HttpLocust):
    host     = "https://github.com/"
    task_set = WebsiteTasks
    min_wait = 5000
    max_wait = 15000

 

参数化

做用:循环取数据,数据可重复使用

 例如:模拟3个用户并发请求网页,共有100个URL地址,每一个虚拟用户都会依次循环加载100个URL地址

from locust import TaskSet, task, HttpLocust
class UserBehavior(TaskSet):
    def on_start(self):
        self.index = 0
    @task
    def test_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)
class WebsiteUser(HttpLocust):
    host = 'http://debugtalk.com'
    task_set = UserBehavior
    share_data = ['url1', 'url2', 'url3', 'url4', 'url5']
    min_wait = 1000
    max_wait = 3000

 保证并发测试数据惟一性,不循环取数据;

 全部并发虚拟用户共享同一份测试数据,而且保证虚拟用户使用的数据不重复;

例如:模拟3用户并发注册帐号,共有9个帐号,要求注册帐号不重复,注册完毕后结束测试:

采用队列

from locust import TaskSet, task, HttpLocust
import queue
class UserBehavior(TaskSet):
    @task
    def test_register(self):
        try:
            data = self.locust.user_data_queue.get()
        except queue.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)
class WebsiteUser(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 = 1000
    max_wait = 3000

保证并发测试数据惟一性,循环取数据;

全部并发虚拟用户共享同一份测试数据,保证并发虚拟用户使用的数据不重复,而且数据可循环重复使用;

例如:模拟3个用户并发登陆帐号,总共有9个帐号,要求并发登陆帐号不相同,但数据可循环使用;

from locust import TaskSet, task, HttpLocust
import queue
class UserBehavior(TaskSet):
    @task
    def test_register(self):
        try:
            data = self.locust.user_data_queue.get()
        except queue.Empty:
            print('account data run out, test ended')
            exit(0)
        print('register with user: {0}, pwd: {1}' .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)
class WebsiteUser(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 = 1000
    max_wait = 3000

 

断言(即检查点)

性能测试也须要设置断言么? 某些状况下是须要,好比你在请求一个页面时,就能够经过状态来判断返回的 HTTP 状态码是否是 200。

经过with self.client.get("url地址",catch_response=True) as response的形式;

response.status_code获取http响应码进行判断,失败后会加到统计错误表中;

python自带的断言assert失败后代码就不会向下走,且失败后不会被Locust报表统计进去;

默认不写参数catch_response=False断言无效,将catch_response=True才生效;

下面例子中:

首先使用python断言对接口返回值进行判断(python断言不经过,代码就不向下执行,get请求数为0),经过后对该接口的http响应是否为200进行判断;

@task
def all_interface(self):
     #豆瓣图书api为例子
     with  self.client.get("https://api.douban.com/v2/book/1220562",name="/LhcActivity/GetActConfig",catch_response=True) as response:
      assert response.json()['rating']['max']==10            #python断言对接口返回值中的max字段进行断言
            if response.status_code ==200:                   #对http响应码是否200进行判断
                response.success()
            else:
                response.failure("GetActConfig[Failed!]")

 

5、Locust运行模式

运行Locust时,一般会使用到两种运行模式:单进程运行多进程分布式运行

单进程运行模式

Locust全部的虚拟并发用户均运行在单个Python进程中,具体从使用形式上,又分为no_webweb两种形式。该种模式因为单进程的缘由,并不能彻底发挥压力机全部处理器的能力,所以主要用于调试脚本和小并发压测的状况。

当并发压力要求较高时,就须要用到Locust的多进程分布式运行模式。从字面意思上看,你们可能第一反应就是多台压力机同时运行,每台压力机分担负载一部分的压力生成。的确,Locust支持任意多台压力机(一主多从)的分布式运行模式,但这里说到的多进程分布式运行模式还有另一种状况,就是在同一台压力机上开启多个slave的状况。这是由于当前阶段大多数计算机的CPU都是多处理器(multiple processor cores),单进程运行模式下只能用到一个处理器的能力,而经过在一台压力机上运行多个slave,就能调用多个处理器的能力了。比较好的作法是,若是一台压力机有N个处理器内核,那么就在这台压力机上启动一个masterNslave。固然,咱们也能够启动N的倍数个slave,可是根据个人试验数据,效果跟N个差很少,所以只须要启动Nslave便可。 

no_web形式启动locust:

若是采用no_web形式,则需使用--no-web参数,并会用到以下几个参数。

  • -c, --clients:指定并发用户数;
  • -n, --num-request:指定总执行测试次数;
  • -r, --hatch-rate:指定并发加压速率,默认值位1。

示例:

$ locust -f    locustfile.py     --host = xxxxx.com   --no-web -c 1 -n 2

在此基础上,当咱们想要调试Locust脚本时,就能够在脚本中须要调试的地方经过print打印日志,而后将并发数和总执行次数都指定为1

$ locust -f    locustfile.py     --host = xxxxx.com   --no-web -c 1 -n 1

执行测试

经过这种方式,咱们就能很方便地对Locust脚本进行调试了。

Locust脚本调试经过后,就算是完成了全部准备工做,能够开始进行压力测试了。

web形式启动locust:

若是采用web形式,,则一般状况下无需指定其它额外参数,Locust默认采用8089端口启动web;若是要使用其它端口,就可使用以下参数进行指定。

  • -P, --port:指定web端口,默认为8089.
  •  终端中--->进入到代码目录: locust     -f    locustfile.py     --host = xxxxx.com      
  • -f            指定性能测试脚本文件
  • -host      被测试应用的URL地址【若是不填写,读取继承(HttpLocust)类中定义的host】
  • 若是Locust运行在本机,在浏览器中访问http://localhost:8089便可进入Locust的Web管理页面;若是Locust运行在其它机器上,那么在浏览器中访问http://locust_machine_ip:8089便可。

多进程分布式运行

无论是单机多进程,仍是多机负载模式,运行方式都是同样的,都是先运行一个master,再启动多个slave

启动master时,须要使用--master参数;一样的,若是要使用8089之外的端口,还须要使用-P, --port参数。

D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --master --port=8089
[2018-06-05 15:36:30,654] dengshihuang/INFO/locust.main: Starting web monitor at *:8089
[2018-06-05 15:36:30,684] dengshihuang/INFO/locust.main: Starting Locust 0.8.1

启动slave时须要使用--slave参数;在slave中,就不须要再指定端口了。master启动后,还须要启动slave才能执行测试任务。

D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --slave
[2018-06-05 15:36:30,654] dengshihuang/INFO/locust.main: Starting web monitor at *:8089
[2018-06-05 15:36:30,684] dengshihuang/INFO/locust.main: Starting Locust 0.8.1
D:\workSpaces\ApiAutoTest\TestCases\OpsUltraAPITest\MonitorAPITest>locust -f monitorAgent.py --slave --master-host=<locust_machine_ip>

masterslave都启动完毕后,就能够在浏览器中经过http://locust_machine_ip:8089进入Locust的Web管理页面了。使用方式跟单进程web形式彻底相同,只是此时是经过多进程负载来生成并发压力,在web管理界面中也能看到实际的slave数量。若是slavemaster不在同一台机器上,还须要经过--master-host参数再指定master的IP地址。

运行结果:

 

 Number of users to simulate    设置虚拟用户数,对应中no_web模式的-c, --clients参数;

 Hatch rate(users spawned/second)每秒产生(启动)的虚拟用户数 , 对应着no_web模式的-r, --hatch-rate参数,默认为1。点击Start swarming 按钮,开始运行性能测试。

上图:启动了一个 master 和两个 slave,由两个 slave 来向被测试系统发送请求

性能测试参数

  • Type: 请求的类型,例如GET/POST。

  • Name:请求的路径。这里为百度首页,即:https://www.baidu.com/

  • request:当前请求的数量。

  • fails:当前请求失败的数量。

  • Median:中间值,单位毫秒,一半的服务器响应时间低于该值,而另外一半高于该值。

  • Average:平均值,单位毫秒,全部请求的平均响应时间。

  • Min:请求的最小服务器响应时间,单位毫秒。

  • Max:请求的最大服务器响应时间,单位毫秒。

  • Content Size:单个请求的大小,单位字节。

  • reqs/sec:是每秒钟请求的个数。

 相比于LoadRunnerLocust的结果展现十分简单,主要就四个指标:并发数RPS响应时间异常率。但对于大多数场景来讲,这几个指标已经足够了。

在上图中,RPS平均响应时间这两个指标显示的值都是根据最近2秒请求响应数据计算获得的统计值,咱们也能够理解为瞬时值。

若是想看性能指标数据的走势,就能够在Charts栏查看。在这里,能够查看到RPS平均响应时间在整个运行过程当中的波动状况。

除了以上数据,Locust还提供了整个运行过程数据的百分比统计值,例如咱们经常使用的90%响应时间响应时间中位值;平均响应时间和错误数的统计,该数据能够经过Download response time distribution CSV和Download request statistics CSV得到,数据展现效果以下所示。

 

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

注意:

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明显比较长

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

好文推荐:

一、https://debugtalk.com/post/locustplus-talk-about-performance-test/

这篇博客从性能测试方法、性能瓶颈定位、性能测试工具的基本组成、性能测试工具推荐(比较了loadrunner,jmeter,Locust优缺点)等方面作了深刻的介绍,推荐!

蝗虫比Jmeter好的一点就是高并发,可是相对的很差的地方也有,就是须要另外的工具去监控服务器,并且须要去编写代码。