Locust学习总结

简介

Locust是一个使用Python编写的可扩展、分布式的开源性能测试工具。

优点

  • 相比于Jmeter、LoadRunner这种基于GUI的工具而言,Locust使用Python语言来描述测试场景使模拟用户行为变得更加灵活和简洁,除了Http(s)协议之外,Locust可以测试任意协议的系统,只需要实现Python调用对应协议的库进行请求即可(类似HttpLocust类)。
  • Locust的并发机制采用协程的方式,相比于进程和线程减少了系统级资源调度,因此单机的产生的并发能力相比于LoadRunner、jmeter得到了大幅的提升。

安装

pip install locust

Locust脚本编写

import queue
from locust import HttpLocust, TaskSet, task
from locust.clients import HttpSession
from sign import ParserData


class UserBehavior(TaskSet):

    parser_data = ParserData()  # 解析接口传参类
    _client = 20
    version = 119
    user_info = None

    @staticmethod
    def get_user_info(response):
        r = response.json().get('content')
        return {
            'market_id': r.get('marketId'),
            'token': r.get('token')
        }

    def on_start(self):
        try:
            user, password = self.locust.users.get_nowait()
        except queue.Empty:
            print('test data run out. test ended.')
            exit(0)
        client = HttpSession(base_url='http://login.xxxx.cn')
        data = self.parser_data(loginName=user,
                                password=password,
                                client=self._client,
                                version=self.version)
        response = client.post(url='/login', data=data)
        self.user_info = self.get_user_info(response)
        self.locust.users.put_nowait((user, password))

    @task(2)
    def index(self):
        url = '/index'
        data = self.parser_data(market_id=self.user_info['market_id'],
                                client=self._client,
                                version=self.version,
                                pnum='3')
        headers = {'Authorization': 'Barer:' + self.user_info['token'],
                   'Accept': 'application/vnd.hs-api.v1+json'}
        with self.client.post(url=url, data=data, headers=headers,
                              verify=False, catch_response=True) as response:
            if response.status_code == 200:
                response.success()
            else:
                response.failure('http error.')

    @task(1)
    def shop_car_list(self):
        url = '/shopCar/list'
        data = self.parser_data(market_id=self.user_info['market_id'],
                                ischaidan='1',
                                client=self._client,
                                version=self.version)
        headers = {'Authorization': 'Bearer:' + self.user_info['token'],
                   'Accept': 'application/vnd.hs-api.v1+json'}
        with self.client.post(name='ShopCar', url=url, data=data, headers=headers,
                              verify=False, catch_response=True) as response:
            if response.status_code != 200 or "失败" in response.text:
                response.failure('response error.')
            else:
                response.success()


class Stay(TaskSet):

    index = 0

    def on_start(self):
        self.index += 1

    @task
    def get_error(self):
        response = self.client.get('/1', name='error', allow_redirects=False,
                                   verify=False, catch_response=True)
        if response.status_code == 200:
            response.success()
        else:
            response.failure('http error.')

    @task
    def logout(self):
        self.interrupt()


class User(TaskSet):

    tasks = {Stay: 1}

    @task(1)
    def user(self):
        self.client.get('/', verify=False)


class WebsiteUser(HttpLocust):
    task_set = UserBehavior
    host = 'https://xxxx.api.xxxx.cn'
    min_wait = 1000
    max_wait = 3000
    users = queue.Queue()
    users.put_nowait(('user1', '1232'))
    users.put_nowait(('user2', '1234'))
    users.put_nowait(('user3', '1321'))
    weight = 3
    stop_timeout = 20


class WebsiteU(HttpLocust):
    task_set = User
    host = 'https://www.baidu.com'
    min_wait = 0
    max_wait = 0
    weight = 1
    stop_timeout = 60

简单解释下:

  • UserBehavior和WebsiteUser两个类实现测试场景使用3个用户账号,每个用户会去先登录,然后分别去查看首页和进入购物车页面
  • 首先导入了需要用到的类,HttpLocust类为Locust子类,模拟客户端的请求类,Taskset类为任务集类,task为任务装饰器。

Taskset

  • UserBehavior为Taskset子类,该类主要用来定义每个虚拟用户的操作行为

  • Taskset子类中可以定义一个on_start方法在正式开始测试前只执行一次,相当与初始化操作(这里说的只执行一次是每个虚拟用户都会去执行一次),比如获取登录token等操作。

  • teskset类中的每个任务都需要用@task(weight=1)装饰器去装饰为一个任务,weight为执行的权重,如果不装饰,locust不会认为这是一个任务,UserBehavior类中@task(1)、@task(2)装饰器表示3个用户里面有2个用户去模拟执行index方法,有1个用户去执行shop_car_list方法

  • taskset类中self.client属性请求操作时传入catch_response参数,设置为True,可以标记响应结果为成功或失败,即使响应是成功的,也可以标记为失败,默认为Fasle

  • taskset类中self.client属性请求操作时有一个name参数,当设置了name的值时,最后的请求结果展示中name字段会显示这里定义的name值,相当与给这个方法起了一个别名.

  • taskset类中interrupt(reschedule=True)方法在顶层的taskset类(即被指定到Locust子类中的taskset)中不可用,reschedule为True时,从被嵌套的任务中出来立即执行新的任务,如果为False从被嵌套的任务中出来会等待min_time-max_time之间的随机时间,然后再执行新的任务,这个方法主要用来跳出嵌套的任务集

HttpLocust

  • WebsiteUser为HttpLocust子类,该类是用来模拟用户的类,定义了一些用户信息,及请求方式

  • HttpLocust子类中task_set属性用来指定模拟用户执行的操作,即Taskset子类

  • HttpLocust子类中的host属性为被测试系统的host,当命令行中没有指定--host参数时,此属性会生效

  • HttpLocust子类中的min_wait、max_weight为最大等待时间和最小等待时间,每个请求会从这两个时间间隔中随机取一个时间等待,相当用户实际操作系统时每个动作的思考时间。若测试单个接口则对应的值都设置为0即可。如果Taskset类中定义了min_wait、max_weight则会覆盖Locust子类中定义的值。单位ms,默认值1000ms

  • HttpLocust子类中的stop_timeout属性为执行测试的时间,单位为s

  • HttpLocust子类中的weight为该类执行的权重,当有多个子类时生效,如WebsiteUser、WebsiteU两个HttpLocust子类中weight值分别为3和1.

  • Locust默认单机单进程运行,此模式下并不能充分利用单机的多处理器,可使用分布式运行,即开启一个master,n个slave(n为处理器个数),master负责启动Locust的web服务和任务分发,不会产生压力,slave主要负责产生压力

运行模式:

no-web模式

no_web模式指在命令行中直接运行

locust -f load_test.py -c 1 -r 1 -n 1
  • -f 指定要运行的Locust性能测试文件
  • -c 指定模拟的并发用户数
  • -r 指定每秒的启动用户数
  • -n 指定运行次数
  • -t 指定运行的时间,例如300s,1m,1h
    写完脚本调试时可在该模式下运行

单机单进程运行

locust -f load_test.py

分布式运行

分布式运行,有单机多进程运行和多机多进程运行两种

locust -f load_test.py --master       master模式下启动locust
locust -f load_test.py --slave         启动一个locust slave节点,单机多进程模式
locust -f load_test.py --slave --master-host=192.168.105.11    启动一个locust slave节点,多机模式下 
no_web模式下运行
image.png
web模式
image.png
  • Number of users to simulate:需要模拟的虚拟用户个数
  • Hatch rate (users spawned/second):启动虚拟用户的速率,每秒产生出多少个用户数


    QQ图片20171109190334.png
  • 显示并发数、响应时间、异常率、每秒请求数等
  • reqs/sec(每秒请求数)为根据最近2s请求数据计算得到的数据,即瞬时值


    QQ图片20171109190430.png
  • 显示rps、响应时间、并发数在整个测试运行中的走势图


    QQ图片20171109190455.png
  • 显示测试过程中出现的所有失败的请求

Exceptions显示测试过程中出现的异常
Download Date提供测试结果csv文件的下载

测试数据:

  • locust子类中设置的数据是全局的,为list时,使用自增方式取数据,并发运行时会出现取到的数据重复的情况,如果对数据唯一性有要求,使用python的queue队列的数据结构即可
  • taskset子类中设置的数据是局部的,即每一个虚拟用户都会有一个属于自己的这个变量

queue数据结构

队列形式

q=queue.Queue(maxsize=3)       先进先出队列
q.put(1)      向队列中存数据
q.get()        向队列中取数据
q.put_nowait()       相当于q.put(1, block=False),当q队列满了之后put会触发queue.Full异常
q.get_nowait()       相当与q.get(block=False),当q队列为空之后get会触发queue.Empty异常
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容