开源压测工具Locust
locust是流行的开源性能测试工具,其压测脚本就是python代码,所以特点是简单,灵活.
之前使用的场合比较多,汇总些笔记供参考.
安装及依赖
pip install locust
注: 可以在Windows做开发调试,不建议做实际运行,性能较差
Locust主要基于以下库实现:
- gevent/greenlet: 轻量级异步线程
- msgpack-python: master和slave通讯的一种高效消息格式
- flask/jinja2/werkzeug: web界面的实现
Windows安装
- 安装gevent错误修复:
修复Python库 Windows安装错误:error Microsoft Visual C++ 14.0 is required 安装Microsoft Build Tools for Visual Studio
下载vs_buildtools.exe并选择Workloads → C++ build tools -> Windows 10 SDK安装。
- 启动时web页面打不开问题解决:需指定–web-host参数
locust –web-host=127.0.0.1
使用
默认的压测脚本为本地目录的locustfile.py
具体的用法见locust -h
locust -H <my_url> -f <my_locust_file> -c 120 -n 10000 --no-web --only-summary
Web管理页面方式
执行完命令后,访问本地或Master的IP地址, http://127.0.0.1:8089 就可以看到web控制台了.
常用选项
示例:
locust --tags 'tag1'
执行相关:
-t RUN_TIME, --run-time RUN_TIME
Stop after the specified amount of time, e.g. (300s, 20m, 3h, 1h30m, etc.). Only used together with --headless or --autostart. Defaults to run forever.
--autoquit AUTOQUIT
Quits Locust entirely, X seconds after the run is finished. Only used together with --autostart. The default is to keep Locust running until you shut it down using CTRL+C
任务过滤:
Tag options:
Locust tasks can be tagged using the @tag decorator. These options let specify which tasks to include or exclude during a test.
-T [TAG [TAG ...]], --tags [TAG [TAG ...]]
List of tags to include in the test, so only tasks with any matching tags will be executed
-E [TAG [TAG ...]], --exclude-tags [TAG [TAG ...]]
List of tags to exclude from the test, so only tasks with no matching tags will be executed
User classes:
UserClass Optionally specify which User classes that should be used (available User classes can be listed with -l or --list)
日志:
--loglevel LOGLEVEL, -L LOGLEVEL
Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. Default is INFO.
命令行执行
也支持不使用web页面, 需要指定几个参数值
locust --no-web -c 10 -r 5
# -c == --clients
# -r == --hatch-rate
压测脚本开发
基本功能
# 记录日志,默认INFO
import logging
# 常用模块和类
from locust import HttpUser, TaskSet, task, between
class UserTasks(TaskSet):
def on_start(self):
self.client.header = {'Content-Type':'application/json'}
def on_stop(self):
pass
@task(1) # 比例/权重
def get_api(self):
self.client.get("/api/get")
# 支持捕获异常并自定义失败
@task
def post_api(self):
with self.client.post("/api/post",json={"mykey": "myvalue"},headers=self.client.header, verify=False, catch_response=True) as response:
logging.debug(response.text)
if not response.headers['errorCode'] == '0':
response.failure(response.headers['errorMessage'])
class WebsiteUser(HttpUser):
host = "https://127.0.0.1:8000"
wait_time = between(1, 3) # 随机延迟
tasks = [UserTasks]
增加集合点
from gevent.lock import Semaphore
all_users_spawned = Semaphore()
all_users_spawned.acquire()
@events.init.add_listener
def _(environment, **kw):
@environment.events.spawning_complete.add_listener
def on_spawning_complete(**kw):
# 释放锁
all_users_spawned.release()
class UserTasks(TaskSet):
def on_start(self):
all_users_spawned.wait()
使用预生成数据
# 获取随机
global USERS
USERS = get_user_list() # 自定义实现
class UserTasks(TaskSet):
def on_start(self):
self.client.user = USERS.pop() # 选取某模拟用户
禁用 InsecureRequestWarning: Unverified HTTPS request is being made to host
import urllib3
urllib3.disable_warnings()
高级用法
使用固定的RPS
from locust import constant_pacing
class WebsiteUser(HttpUser):
wait_time = constant_pacing(1) # fixed RPS rate
集成prometheus
主要步骤:
- 配置prometheus/prometheus.yml,之后启动
scrape_configs:
- job_name: locust
metrics_path: '/export/prometheus'
static_configs:
- targets: ['127.0.0.1:8089'] # 地址修改为实际地址
-
locust启动后(参考我的fork示例),访问exporter URL做简单验证: http://127.0.0.1:8089/export/prometheus
-
访问http://127.0.0.1:9090/,在Expression输入 locust_stats_current_rps并点击Execute,就可以图形报告了。
-
如果需要Grafana展现的话,配置数据源之后导入Dashboard ID: 12081就可以了。
Go扩展 Boomer
以examples/main.go为例
go get -u github.com/myzhan/boomer@master
# 注:默认master端口为5557,不要修改
go build main.go
# 调试,只运行一次
./main --run-tasks foo,bar # 或者 go run --run-tasks foo,bar
# 其他选项
--master-host=127.0.0.1 # 默认为127.0.0.1
--max-rps=0
--request-increase-rate
// 限制最大RPS
ratelimiter := boomer.NewStableRateLimiter(100, time.Second)
log.Println("the max rps is limited to 100/s.")
// 限制RampUp生成速度
ratelimiter, _ := boomer.NewRampUpRateLimiter(1000, "100/1s", time.Second)
log.Println("the max rps is limited to 1000/s, with a rampup rate 100/1s.")
globalBoomer.SetRateLimiter(ratelimiter)
globalBoomer.Run(task1)