性能测试工具 基于 Python 的性能测试工具 locust (与 LR 的简单对比)

among29 · 发布于 2016年5月10日 · 最后由 jinglebell 回复于 2017年2月24日 · 2115 次阅读
本帖已被设为精华帖!

背景

最近自己开发了一个小的接口,功能测完了,突然想测下性能,原来做性能测试,我一直用的是HP的LoadRunner,前一段时间正好看过locust,想想就用这个来测测性能吧。
由于对LR比较熟,正好做个对比,这样更利于对新东西的理解。

基础

locust 的官网:http://locust.io/

也可以参考论坛里其他同学的介绍:https://testerhome.com/topics/2888

目前locust还只支持Python 2版本。

测试需求

验证在相同的服务器端的情况下,使用LR和locust分别进行性能测试,在相同并发用户的情况下,验证平均响应时间,TPS值等性能测试指标的差异。
为了方便,使用http协议,一个get请求,一个post请求,交易比例为1:1。

服务器端

为了简单易理解,用Python的bottle框架写了一个服务器端,2个交易,一个get,一个post请求,交易中加了2个不同的sleep。
代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

__author__ = 'among,lifeng29@163.com'

from bottle import *
from time import sleep

app = Bottle()


@app.route('/transaction_1', method='GET')
def tr1():
    sleep(0.2)
    resp = dict()
    resp['status'] = 0
    resp['value'] = 'xxx'
    return resp


@app.route('/transaction_2', method='POST')
def tr2():
    parm1 = request.forms.get('parm1')
    parm2 = request.forms.get('parm2')
    sleep(0.5)
    resp = dict()
    resp['status'] = 0
    resp['value'] = 'yyy'
    return resp


run(app=app, server='cherrypy', host='0.0.0.0', port=7070, reloader=False, debug=False)

服务器端部署在一个单独的Windows的机器中,基于Python 3,启动后,监听7070端口。

LR中的测试脚本

在另外的一个Windows机器中,使用LR 11,用的是http/html协议的脚本,主要代码如下:
用了2个action,用于划分交易比例。
action1:

Action1()
{
    lr_start_transaction("get");
    web_reg_find("Text=xxx",
        LAST);
    web_custom_request("Head",
        "URL=http://10.0.244.108:7070/transaction_1", 
        "Method=GET",
        "Resource=0",
        "Referer=",
        LAST);
    lr_end_transaction("get", LR_AUTO);
    return 0;
}

action2:

Action2()
{
    lr_start_transaction("post");
    web_reg_find("Text=yyy",
        LAST);  
    web_custom_request("Head",
        "URL=http://10.0.244.108:7070/transaction_2", 
        "Method=POST",
        "Resource=0",
        "Referer=",
        "Body=parm1=123&parm2=abc",
        LAST);
    lr_end_transaction("post", LR_AUTO);
    return 0;
}

使用1:1的比例设置2个transaction的执行比例:

LR中的执行方法,直接放到场景中,执行即可。

locust中的测试脚本

在另外的mac中,使用locust执行测试,全部通过代码实现。代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

__author__ = 'among,lifeng29@163.com'

from locust import *

class mytest(TaskSet):
    @task(weight=1)
    def transaction_1(self):
        with self.client.get(name='get', url='/transaction_1', catch_response=True) as response:
            if 'xxx' in response.content:
                response.success()
            else:
                response.failure('error')

    @task(weight=1)
    def transaction_2(self):
        dt = {
            'parm1': '123',
            'parm2': 'abc'
        }

        with self.client.post(name='post', url='/transaction_2', data=dt, catch_response=True) as response:
            if 'yyy' in response.content:
                response.success()
            else:
                response.failure('error')


class myrun(HttpLocust):
    task_set = mytest
    host = 'http://10.0.244.108:7070'
    min_wait = 0
    max_wait = 0

具体的参数可以查看官方文档。

其中:

  1. 主类继承HttpLocust,用于测试http协议的系统;
  2. min_wait和max_wait用于设置执行task过程中的等待时间,相当于LR中Pacing的设置,这里都设置为0;
  3. task装饰器类似于LR中的事务,可以做嵌套;
  4. weight相当于权重,如2个事务是1:1,保持比例一致就行;
  5. 这里写了2个事务,分别为get和post;对response的判断通过python的语法实现,类似于LR中的检查点。

执行方法,通过命令行启动:
如下图:

LR中的测试过程和结果

测试过程:
直接设置并发用户数和加载方式,10个用户并发,同时加载就可以了。

测试结果:
平均响应时间:

TPS:

事务:

Locust中的测试过程和结果

测试过程:
使用浏览器打开http://127.0.0.1:8089

设置需要的并发用户数和用户加载策略。
这里设置相同的10用户并发,Hatch Rate是每秒启动多少用户的意思。这里设置为10,就是同时启动10个了。注意,这里不好设置执行多久,和LR不一样。(可以不启动浏览器,直接在启动参数中设置并发用户数,执行多少个事务后结束,具体用-h可以看到帮助)

启动执行后:


其中,Average中为平均响应时间等测试指标,最后一列的reqs/sec相当于LR中的TPS。(这里locust把它叫做rps),其他指标都比较好理解了。

最后的结果:
在web页面中可以下载原始的测试结果数据。
在停掉python命令后,在终端中也可以看到一些信息,最后的一行是百分之X的响应时间,表示百分之多少的交易在XXX响应时间内。
这里比LR中的要多点,包括了50%到100%的响应时间。

结果比较

在相同的服务器端环境,测试的结果值相似,没有多大的区别。
在设置交易比例的过程中,可以看到get和post交易的比例都存在差异。这个也无法避免(除非自己写脚本划分)。所以tps方面存在些差异。不过总体差距很小。

总结

性能测试,重点是考察并发用户数、响应时间、tps这类指标。

一直用的是LR,LR在一起概念上更易于理解,在有lr的基础上,在看其他的工具,就比较容易了。

locust也可以支持分布式执行(多执行机),用来简单测试这类http的接口,也算比较方便。
而且,locust全部基于Python脚本,扩展性不错,号称可以测试任何协议和系统。

最后,我还是那句话,看什么事情,用什么工具最高效易用,用合适的工具做合适的事情即可。

欢迎大家讨论。

共收到 34 条回复
8139

之前玩过,感觉还是不够通用

—— 来自TesterHome官方 安卓客户端

605

没有二次开发的话功能比较少。

我一开始也有试过,后面还是转 gatling 了。

6504

前端压测工具而已,感觉差不多,不过感觉gatling更强大一点

1990

还真没用过,回头看看,基于python其实是个亮点。

8322

搞个1000并发试试

4863

性能测试的重点不在于压力发起的工具,而在于分析性能测试的需求,设计性能测试场景,尽可能的模拟真实环境中的压力(正常和异常情况)。
无论是LR,locust,gatling,产品本身都有自己的定位和优势,用合适的东西做合适的事情即可。

gatling我还没试过,有机会也可以尝试下。

7458

装好了locustio,脚本运行时报: from locust import HttpLocust, TaskSet,task ImportError: cannot import name HttpLocust 错误,安装过程也没报错,python的Lib下也有locust这个文件夹

96

可以详细把数据的分析展开下么~

6385

难得看到有人介绍locust
locust的底层http调用使用的是requests,如果你们同时还用requests做接口测试的话…
想象下,性能测试直接复用自动化测试的代码,多轻松

211

感谢分享,更喜欢locust这种灵活定制的。

—— 来自TesterHome官方 安卓客户端

7064

学习了

6613

求指教mac上安装locust,我安不上

4863

#12楼 @wanxi3 用pip安装就行了,可能自带的py2的版本没有pip,你先安装pip吧。

6613

#13楼 @among29 我装了pip 用了sudo也不行

6109

请教一个问题,采用locust写脚本的时候,你是怎么调试的?
例如,我写好了一个接口的测试脚本,这个时候我想先运行一遍看是否正确,除了直接运行 locust 看日志外,有没有什么办法可以直接调用呢?

4863

#15楼 @debugtalk

我都是这样的,调试的时候都是连接的代理,这样方便。
一种方法是自己在外面的py中先调试好,然后再放到locust中执行。
另一种是使用命令行启动 locust
如:locust -f loc1.py --no-web -c 1 -n 4
-c是指并发数,-n是执行的次数。少跑点,调试方便。这样配合代理,调试也不复杂。

用命令行还可以自动化执行,执行的结果也可以通过日志或output来分析。

6109

#16楼 @among29 你连接代理的目的是为了看请求和响应情况么?

另外,有没有可能直接在Python文件中调用 HttpLocust, TaskSet 这些类?像如下这种方式?

http_locust = HttpLocust()
uri = HOST + "/api/users/login.json"
payload = {
    'login': 'user1',
    'password': '123456'
}
http_locust.client.post(uri, payload)
6385

#15楼 @debugtalk
注意下locust的setup.py:

entry_points={
        'console_scripts': [
            'locust = locust.main:main',
        ]

能看到locust的执行入口是locust/main.py的main函数

假设你要调试你的脚本,可以这么做:

if __name__ == "__main__":
    import sys
    sys.argv.extend(["-f", __file__])
    from locust.main import main
    main()

4863

我是习惯用代理调试了。如果可以直接import locust的py文件的话, 自己写个py来调试也不错。

6109

#18楼 @jacexh 这种方式是可以直接运行当前文件,但是本质上还是跟在Terminal中直接运行 locust -f test.py 一样的。

我希望实现的目标是只运行单个请求,类似于#16楼中贴的代码那样,有办法实现么?

6385

#20楼 @debugtalk 你把参数补充完不就行了么

sys.argv.extend(["-f", __file__, "--no-web", "-c", "1", "-r", "1"])

另外你还可以定义不同的event

6109

#21楼 @jacexh 嗯,这种方式的确是可以只执行单个请求。但是这样做还是感觉不够完美,因为会初始化一些不相关的类,在结果日志里面展示的内容也比较冗余(当前就只想看到请求对应的响应信息)。

你说的定义不同的event指的是什么呢?可否详细指导下,非常感谢!

6109

#19楼 @among29 直接调用HttpLocust, TaskSet你有试过么?

4863

#23楼 @debugtalk
没,应该可以,不行就要看看源码了。
没这个需求,就没折腾。

6385

#22楼 @debugtalk

def print_something(request_type, name, response_time, response_length, *args):
    print request_type, name, response_time, response_length


events.request_success += print_something
6109

#24楼 @among29 好的,谢谢啦

6109

#25楼 @jacexh 谢谢啦,我去详细了解下

10609

基于python确实不错,只是locust的实用性确实一般

96

换mac后安装locutio时,安装greenlet报错了

96

刚接触性能这块很懵。。
请问下我想用locust做800请求/s 的话 是不是仅需要设置Hatch Rate为800呢,那用户数又是用来做什么的。。

10519

刚实验了jmeter、gatling、locust,前两者结果差不多(7000/s,7800/s)。但是locust仅仅800/s,number user是800,hatch rate也设置了800。

是不是我漏掉了哪些设置?

(应用只是简单的页面,没有任何逻辑)

class locustfile_x(TaskSet):
    @task(1)
    def index(self):
        self.client.get("/")

class WebsiteUser(HttpLocust):
    task_set = locustfile_x
    min_wait = 0
    max_wait = 0
11866
6385jacexh 回复

赞同,但如果是https的接口会麻烦点,尤其是很多前置处理方法是开发用java或其它语言写的私有方法。。

6385
11866jinglebell 回复

为什么https就麻烦了? 只是传输层有层加密而已,如果是证书校验有问题,加上verify=False

11866
6385jacexh 回复

我们的加密算法是自己写的,不是完全用的公共方法,而且入参规则每个项目不一样,在做接口自动化的时候已经踩过一次坑了。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册