接口压测之Locust

发布于:2022-11-10 ⋅ 阅读:(788) ⋅ 点赞:(0)

整理自:

进程/线程/协程:一文读懂什么是进程、线程、协程(建议收藏)

locust相关:

Installation — Locust 2.13.0 documentation(官方)

深入浅出开源性能测试工具 Locust(使用篇) - DebugTalk

Locust使用

需要了解的: 

  • 进程Process:应用程序运行时会在内存空间形成一块拥有独立地址的内存体,是操作系统分配系统资源的最小单位。一个应用程序可有多个进程,一个进程可有多个线程,但至少有一个线程,同一进程的所有线程共享该进程的所有资源。

  • 线程Thread:应用程序执行中一个单一的顺序控制流程,是CPU调度执行的最小单位。一个线程就是执行一个子程序(函数)。一个线程只能属于一个进程,线程不能脱离于进程而存在。

  • 协程Coroutines:完全由应用程序控制,而不是由操作系统内核来管理的更轻量级存在。一个线程可以有多个协程。协程在子程序内部是可中断的,转而执行别的子程序,然后到合适的时候再回来接着执行。

 

 一、locust压测工具

1.1 介绍

  • 开源的、使用python开发、基于事件、支持分布式、提供WEB UI、支持结果导出;

  • 使用python第三方库gevent提供的非阻塞IO和协程Coroutine来实现网络层的并发请求;

  • 采用python的requests库作为客户端;

说明:locust虽然是基于协程请求,但由于locust是运行在python解析器上,所以存在GIL锁机制;默认的网络请求库是requests同步库,所以单进程下的并发不会很高,如果想用locust进行并发请求,必定要使用分布式+异步请求库(同步请求和异步请求)。

1.2 如果非常感兴趣

locust源码:GitHub - locustio/locust: Scalable load testing tool written in Python(可以点击setup.py去查看依赖了哪些python库)

1.3 常用的压测工具对比图

二、locust安装

2.1 mac下的安装方式(使用pip工具安装) 

  • 第一种方式:

pip install locust(这里会默认安装最新版本,已经到1.6.0了,与0.*版本的差异挺大,以下都是讲的新版本locust使用

pip install pyzmq(安装第三方库,让locust能多进程/多机器分布式进行压测)

locust --help(查看locust命令帮助并验证是否安装成功)

  • 第二种方式:

通过GitHub上克隆项目安装(Python3推荐):GitHub - locustio/locust: Scalable load testing tool written in Python ,然后执行python setup.py install

2.2 执行命令及参数说明

执行命令如下:

  • master: locust -f ***x.py --master --master-bind-port 9800 --headless -u 500 -r 200 --expect-worker 10 -t 1m -s 5 --csv locustlog/

  • slave: locust -f ***x.py --master-host localhost --master-port 9800 --headless --worker

参数说明如下:

Command line

Configfile

Description

中文对照

-f, --locustfile

locustfile

Python module file to import,

e.g. ‘../other.py’. Default: locustfile

需要执行脚本的文件及路径

-H, --host

host

Host to load test in the following

format: http://10.21.32.33

压测主机的host

-u, --users

users

Number of concurrent Locust users.

Only used together with –headless

压测并发用户数,

只能与-headless参数一起使用

-r, --hatch-rate

hatch-rate

The rate per second in which users are spawned.

Only used together with –headless

每秒启动用户数,

仅与–headless一起使用

-t, --run-time

run-time

Stop after the specified amount of time,

e.g. (300s, 20m, 3h, 1h30m, etc.).

Only used together with –headless

压测执行时间,

仅与–headless一起使用

--web-host

web-host

Host to bind the web interface to.

Defaults to ‘*’ (all interfaces)

网页上执行压测的host,

默认为*

--web-port, -P

web-port

Port on which to run web host

网页上执行压测的端口

--headless

headless

Disable the web interface,

and instead start the load test immediately.

Requires -u and -t to be specified.

不支持网页压测,需要指定

-u,-t参数一起使用

--web-auth

web-auth

Turn on Basic Auth for the web interface.

Should be supplied in the following

format: username:password

网页执行压测认证,

格式为:username:password

--tls-cert

tls-cert

Optional path to TLS certificate to

use to serve over HTTPS

通过HTTPS服务的TLS证书的路径

--tls-key

tls-key

Optional path to TLS private key to

use to serve over HTTPS

通过HTTPS服务的TLS私钥的路径

--master

master

Set locust to run in distributed mode

with this process as master

分布式运行的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进程运行的host,

默认为*,只能与-master一起使用

--master-bind-port

master-bind-port

Port that locust master should bind to.

Only used when running with –master.

Defaults to 5557

master进程运行的端口,

默认为5557,只能与-master一起使用

--expect-workers

expect-workers

How many workers master should expect

to connect before starting the test

(only when –headless used).

分布式压测的slave个数,

只能与–headless参数一起使用

--worker

worker

Set locust to run in distributed mode

with this process as worker

slave压测进程

--master-host

master-host

Host or IP address of locust master for

distributed load testing.

Only used when running

with –worker. Defaults to 127.0.0.1.

salve压测进程配置的master进程的host,

只能与-worker一起使用

--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

–worker. Defaults to 5557.

salve压测进程配置的master进程的端口,

默认为5557,只能与-worker一起使用

-T, --tags

tags

List of tags to include in the test,

so only tasks with any matching tags will be executed

需要被执行的标签

-E, --exclude-tags

exclude-tags

List of tags to exclude from the test,

so only tasks with no matching tags will be executed

需要被过滤的标签

--csv

csv

Store current request stats to files in CSV format.

Setting this option will generate three files:

[CSV_PREFIX]_stats.csv,

[CSV_PREFIX]_stats_history.csv ,

[CSV_PREFIX]_failures.csv

将请求的统计数据存到csv文件里,

该参数会保存三个csv文件

--csv-full-history

csv-full-history

Store each stats entry in CSV

format to _stats_history.csv file

将每个统计条目存

到 _stats_history.csv 文件

--print-stats

print-stats

Print stats in the console

在控制台中打印统计信息

--only-summary

only-summary

Only print the summary stats

只打印汇总统计

--reset-stats

reset-stats

Reset statistics once hatching has been completed.

should be set on both master and workers

when running in distributed mode

重置统计信息,master和slave

同时设置才生效

--skip-log-setup

skip-log-setup

Disable Locust’s logging setup. Instead,

the configuration is provided by the

Locust test or Python defaults.

禁用日志

--loglevel, -L

loglevel

Choose between

DEBUG/INFO/WARNING/ERROR/CRITICAL.

Default is INFO.

记录日志级别,默认info

--logfile

logfile

Path to log file. If not set, log will go to stdout/stderr

日志记录目录,默认在/stdout/stderr

--step-load

step-load

Enable Step Load mode to monitor how performance

metrics varies when user load increases.

Requires –step-users and –step-time to be specified.

分布式压测逐步增加模式

--step-users

step-users

User count to increase by step in Step Load mode.

Only used together with –step-load

逐步增加的用户数,

只能和--step-load参数使用

--step-time

step-time

Step duration in Step Load mode,

e.g. (300s, 20m, 3h, 1h30m, etc.).

Only used together with –step-load

逐步增加的压测时长,

只能和--step-load参数使用

--exit-code-on-error

exit-code-on-error

Sets the process exit code to use

when a test result contain any failure or error

配置退出执行标签,

当程序执行出错包含这个标签时

-s, --stop-timeout

stop-timeout

Number of seconds to wait for a simulated

user to complete any executing task before exiting.

Default is to terminate immediately.

This parameter only needs to be specified for the

master process when running Locust distributed.

设置等待模拟用户完成任务时间,

默认立即退出

三、locust的基础使用

3.1 locust主要库组成

  • gevent:在Python中实现协程的第三方库。协程又叫微线程Corouine。使用gevent可以获取极高的并发能力;

  • flask:Python的一个web开发框架,和django相当;

  • requests:支持http/https访问的库;

  • msgpack-python:一种快速、紧凑的二进制序列化格式,使用与类似json的数据;

  • six:提供了一些简单的工具封装Python2和Python3 之间的差异;

  • pyzmq:安装这个第三方库,可以把Locust运行在多个进程或多个机器(分布式)

说明:安装locust时会自动检测我们当前python环境中是否已安装这些库;若无,则会安装符合版本要求的库。我们也可以自己先按版本要求把这些库装上,这样再装locust会很快。(库版本要求可在git上查看)

3.2 locust运行模式

  • 单进程运行:Locust所有的虚拟并发用户均运行在单个Python进程中。具体从使用形式上,又分为no_web和web两种形式。该模式由于单进程的原因,并不能完全发挥压力机所有处理器的能力,因此主要用于调试脚本和小并发压测的情况。

  • 分布式运行(通过多进程负载来生成并发压力):多机负载(多台压力机同时运行,每台压力机分担负载一部分的压力生成)、单机多进程(在同一台压力机上开启多个slave的情况,因为当前阶段大多数计算机的CPU都是多处理器)。

说明:

1)关于单机多进程:单进程运行模式下只能用到一个处理器的能力。而通过在一台压力机上运行多个slave,就能调用多个处理器的能力了。比较好的做法是,如果一台压力机有N个处理器内核,那就在这台压力机上先启动一个master,然后开多个窗口逐一启动N个slave(我们也可以启动N的倍数个slave,但是根据试验数据经验,效果和N个差不多,因此只需启动N个slave即可)。

2)关于多机负载:需要在主机中使用--master标记来启用一个locust实例,但是master节点的机器不会发起请求,只会收集数据展示;然后在从机使用--worker标记启动一条到多台locust salve的机器节点,与标记----master-host一起使用(指出master机器的ip/hostname)

3.3 locust使用中必须提到的两个类

如下图所示:TaskSet类、HttpUser类

 

1)HttpUser类:HttpUser类是 Locust 1.x 版本中代替以前老版本中的HttpLocust类,是 User 类的子类,用来定义虚拟用户,让虚拟用户作为客户端具备请求能力。新版locust可以直接在User类下声明@task

  • client属性: a)对于http(s)协议:如上图中,我们为要模拟的用户定义一个WebsiteUser类,继承自HttpUser类。HttpUser类为每个用户提供了一个 client 属性,该属性是HttpSession的一个实例,可用于向负载测试的目标系统发出 HTTP 请求。当测试开始时,Locust 将为它的每个虚拟用户创建一个此类的实例,并且每个虚拟用户会在自己的 gevent 线程中运行这些实例。 b)对于非http(s)协议:需要通过编写钩子触发器events.request_success和 events.request_failure事件来自定义客户端。具体见locust压测rpc协议

  • tasks属性(必填):通过指向一个TastSet类来添加任务,声明要执行的任务集属于哪个类。

  • host属性:被测系统的host。在类中没有指定host,则终端启动locust时要通过–host参数来指定。

  • min_wait/max_wait:每个用户执行两个任务的时间间隔上下限(单位是毫秒),具体数值在上下限中随机取值。不指定时默认时间间隔为1秒。(或者使用wait_time=between(***, ***))

2)TaskSet类:用于定义用户的行为,主要实现了用户执行任务的调度算法(包括规划任务执行顺序schedule_task、挑选下一个任务execute_next_task、执行任务execute_task、休眠等待wait、中断控制interrupt等)。需要在User相关类中定义后才能使用(如上图),因此locust 1.*已经不推荐使用这种,而是推荐都在HttpUser中定义(如下图)。

上图新版代码相关说明:

  • HttpUser类是User类的子类,能够直接在User类下声明@task。

  • wait_time 属性可设置用户在两个任务之间的思考时间,从这个区间中随机取值。更多wait_time 的参数可参考:https://docs.locust.io/en/latest/writing-a-locustfile.html#wait-time

  • self.client 和requests有一样的方法。

  • on_start方法是在一开始执行时,会执行的一个方法,并且只执行一次,和它对应的还有一个on_stop 是在执行结束后调用的。应用场景:login,logout 注:新版移除了 Locust.setup、 Locust.teardown、 TaskSet.setup、 TaskSet.teardown,改用 on_test_start、on_test_stop

  • @tag(*tags) 装饰器的作用就是在执行时使用 -T 或者--tags 1 ,此时,将限制测试只执行tag标记的任务。

3.4 开始执行压测

具体需要查看locsut --help中的参数说明。

简单压测脚本示例test.py

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

from locust import task,TaskSet,HttpUser,events
 
class WebsiteTasks(TaskSet):
    # 声明下面是一个任务
    @task
    def recommend(self):
        # self.client是TaskSet的成员,相当于一个request对象
        res = self.client.get("/game/rank/recommend?scene_id=4084&pagesize=10")
        print(res)
 
class WebsiteUser(HttpUser):
    # 声明执行的任务集是哪个类
    tasks = [WebsiteTasks]
    host = "http://yx-test-01.bcc-bdbl.baidu.com:8500"
    # 最小等待时间和最大等待时间   请求间的间隔时间
    min_wait = 1000
    max_wait = 2000

以下是简单使用,注意写清py文件的路径:

  • 本地执行: 第一步:如果py文件中已经写明被测系统的host,则直接在终端locust -f test.py 第二步:此时可以通过http://localhost:8089或者http://0.0.0.0:8089打开locust的web界面,输入界面中的必填项,点击start后才会开始启动压测。 (locust的web界面默认端口为8089,如果被占用也可通过-P参数来指定)

  • 开发机执行:开发机上运行一定要在终端指定--web-host参数!!!(否则会报错!) 1)单进程运行:

  • 2)单机多进程: 第一步:先在施压机器上启动一个master;

  • 第二步:然后在施压机器上开多个窗口逐一启动N个worker(启动的worker数量最好不要超过机器的处理器数量);

  • 第三步:在web界面输入必填项,开始压测。(界面中可以看到开启的worker数,RPS即QPS)

 3.5 locust的Web UI

 

 

 四、初次使用可能失足

问题一:

从本地对某个机器发送请求:

直接使用locust -f test.py完全没有问题;

 不过由于这里8089端口已经被占用,所以换一个8500,locust -f test.py -P 8500(然后通过如下地址访问locust的WEB UI界面,这里指定了端口)

 

 但是,如果是在某个开发机上(比如阡陌机)向另一台机器发送请求,只写locust -f test.py,运行后会报如下错误:OSError: getsockaddrarg: bad family,locust的web界面也无法通过访问该地址打开

网上说该错误出现是由于ipv4和ipv6的原因,并提供了解决方式(使用python-thrift问题汇总_weixin_33912246的博客-CSDN博客),我企图按照该方式去解决,但是苦于不知道借来的机器的root账户密码,无法修改/etc/hosts文件而作罢(不过我觉得不是这个原因)。

后来,我仔细查看了locust使用帮助(locust —help),发现其中有一个指定WEB UI的参数选项,怀疑是这个方面的原因,因此我尝试使用了locust -f test.py --web-host=10.12.75.161来启动locust压测,发现成功了(注:这里的10.12.75.161是施压机器的ip,没有特意指定端口,直接使用的locust的web界面默认端口8089)。开发机上使用locust,一定要指定--web-host参数!!

问题二:

如果出现如下端口占用问题,解决方式为:

 先执行命令找占用的端口:netstat -tunlp

 然后执行命令杀死进程:kill -9 21309

PS:攻略问答卡压测

攻略问答卡压测脚本

攻略问答卡压测脚本test.py

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

from locust import task,TaskSet,HttpUser,events,between
import json
import requests
import time,os,queue
from locust.exception import LocustError
from geventhttpclient import HTTPClient
from geventhttpclient.url import URL
import linecache
import random
 
class WebsiteTasks(TaskSet):
    # 声明下面是一个任务
    # def on_start(self):
    #     '''初始化数据'''
    #     url = URL("http://10.103.64.34:8707")
    #     self.http = HTTPClient(url.host)

    @task
    def recommend(self):
        randomLine = random.randrange(1, 1488)
        query = linecache.getline(r'rand_query_1k_uniq.txt', randomLine)

        inputParams = {
            'query': '原神攻击力暴击属性规律探究',
            'srcid': '5859',
            'tn': 'baidu',
            'dspName': 'iphone',
            'pn': '0',
            'rn': '10'
        }
        inputParams['query'] = query
        
        res = self.client.get("/digital-reading/game/game", params = inputParams)
        print(json.dumps(res.json()))
        print(res)

    # def on_stop(self):
    #     '''销毁数据'''
    #     self.http.close()
 
class WebsiteUser(HttpUser):
    # 声明执行的任务集是哪个类
    tasks = [WebsiteTasks]
    host = "http://10.103.64.34:8707"

    # 最小等待时间和最大等待时间   请求间的间隔时间
    min_wait = 1000
    max_wait = 2000

网站公告

今日签到

点亮在社区的每一天
去签到