Locust是一种基于python语言的压测框架,本质上是基于gevent的多协程机制。这里协程跟线程(thread)的区别是切换开销小、可以由用户控制切换。但是一个线程基本上同时只能运行一个协程,所以从理论上来说协程性能并没有线程好,但在不同的场景应用下还是有些区别的。
Locust的安装
Locust对python2和python3均支持,但现在python2已经不再更新,所以使用python3为主。那么我们要根据实际的压测机器来选择具体的python版本,然后再确定Locust的版本。目前windows7依然有很高的使用率,如果不巧你的压测机器是windows7的话就只能找python3.6的版本(windows7最高支持到3.6),如果不是那么可以选更高的python版本,越新的越稳定的越好。
可以在Locust源码页面里看到各版本的Locust所支持的python版本,https://github.com/locustio/locust。选好版本后就可以进行安装了,根据你是windows还是linux或者mac系统选择合适的安装方式。与python的基本第三方包一样,Locust安装会自动把需要的包都自动安装好,我们需要注意的是有一些第三方包可能跟你的系统相冲突。其中最主要的就是gevent库、greenlet库(这两个是协程相关库,跟性能和稳定性息息相关)、msgpack库(这个在实际中也遇到过)。对这些库可以进行回退或者选择合适的版本,可以在这些第三方库的官方网站找相关线索。直接在python官方网址搜索库名即可,https://www.python.org/。
以windows举例,可以使用pip进行安装,在cmd窗口输入如下命令(假设安装的版本是2.4.1):
pip install locust==2.4.1
目前pip国内经常会卡顿,遇上速度较慢可以使用国内镜像源:
pip install locust==2.4.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
安装好之后可以使用pip命令查看locust和其所需要的第三方包版本:
pip -list
locust的源码位置在你的python安装目录下,有时可根据需求进行修改:
C:\Python36\Lib\site-packages\locust
Locust的基本使用
如果是进行简单的Http压测,那么可以从一个简单的HttpLocust入手:
class UserBehavior(TaskSet):
@task()
def init(self):
... # 一次http请求
class WebsiteUser(HttpLocust):
host = '0.0.0.0' # 某个ip或域名
task_set = UserBehavior # 自己定义的类
min_wait = 0
max_wait = 1000
如此,就是一个简单的Locust框架。min_wait和max_wait是必须自定义的,他们代表请求间隔的范围,框架会自动在这个范围里随机一个时间出来。TaskSet和@task是Locust的固定用法,每次每个协程(Locust的用户)会在TaskSet中随机选一个进行执行,Locust也提供顺序TaskSet等不同需求。
写完脚本需要执行起来了,这里就是告诉Locust帮我生成用户进行压测,前面我们已经设置了请求的间隔,那么运行起来之后我们可以设定Locust最终生成多少用户进行请求以及孵化这些用户的效率。
上面的代码我们找一个新的文件保存起来,起个脚本的名字,如some_http_request.py。然后在cmd窗口可输入以下命令:
locust -f some\_http\_request.py --web-host=127.0.0.1
locust有很多种运行方式,可参考官方文档,这里是单机执行,即只有一台压测机情况。同时使用网页开启,开启网页的ip这里是配置在了本机上,可根据需要修改。执行完cmd命令后,可打开浏览器(尽量不要使用ie):127.0.0.1:8089。ip是前面设定的保持一致,端口号则在源码中,如有冲突可以根据需求去源码中修改。打开之后:
Nubers of users是总的用户数量,其实就是压测其来之后locust会孵化多少个协程出来进行压测,而Spawn rate则是孵化用户的数量,所以刚开始压测时候你会发现rps可能跟你预设的不符,原因就在这。这里也是方便了测试服务器在刚开始承压和一段时候的承压能力的不同。
压测之后可以从网页上下载压测报告,有实时曲线可以看到response time和rps,有时服务器的承压能力不够会出现response time无限增大或者为0(极少数短时间没有返回),此时rps可能达不到预期或很低甚至接近于0,因为locust总共就会孵化设定好的用户,每个用户都按设定的时间间隔来请求,当本次请求时间过长或者没有返回时候,下次请求就不会发生,所以rps统计会极低。
Locust的多机使用
当压测机不止一台时候,通常情况是因为一台满足不了所需要的性能要求(特别当rps需求过高的时候,需要的协程用户更多),就需要多台机器一起进行压测了。
Locust支持一台master和多台worker(更早版本叫slave)形式。这时候通常压测脚本不要需要变动,在master机器和worker机器上使用不同的cmd命令即可。
master机器上:
locust -f some\_http\_request.py --web-host=127.0.0.1 --master --master-host=127.0.0.1
worker机器上:
locust -f some\_http\_request.py --worker --master-host=127.0.0.1
如果master机器也需要执行压测,即不仅仅是做控制和统计来用,那么也可以执行worker的命令,同时兼有worker的运行。注意检测下压测机器的性能即可,在cpu、内存、硬盘、io等指标上不要超标导致压测结果不准确,这里主要注意的就是cpu和内存。
注意web-host的部署仅仅是配置了控制网页的机器,不要求此机器一定要和master机器一致。特别是在Linux作为压测机器时候,如果把windows机器作为控制页面的机器,master和worker机器都是Linux,就会很方便控制压测和获取报告,这里要注意的就是master、worker和控制页面机器要互相能够ping通。
Locust实际中常见的问题
1. 基于Locust的Http压测
针对Http接口,对服务器进行性能压测或者自动化的接口测试是比较常见的测试内容。Locust对Http接口提供了request库基本请求,并提供了一种FastHttpUser更高效的方案。后者可以参考官方文档https://docs.locust.io/en/stable/increase-performance.html。使用时候直接把HttpUser换成FastHttpUser 即可,访问url一样使用request方法。
# 2. 针对非Http的压测
如前文所述,Locust是一种多协程压测的框架,本质上是利用多协程进行同时间多次(就是所谓的rps或者tps)对接口进行访问,已达到一定的压力。比较常见的就是socket连接,包含Websocket等。那么我们可以选择使用python的第三方socket库进行接口访问,这时只需要把连接的IP、端口号和密钥(如果有)准备好建立好连接,之后进行约定好的请求和接收信息即可。
Locust所提供的内部类在每次的task请求时进行一次,如果task里面我们进行了一次socket请求,那么计算rps或tps就按正常计算即可,如果多次,按照理论加倍。当然与Http请求不一样我们在socket请求之前只需要进行一次建立连接即可,这部分最好不要算到请求时间的计算内,否则会影响rps的统计。
# 3. 关于性能上限
windows的压测机器一个cmd窗户即一个worker里的用户数量不能超过1024,这是由于windows的句柄限制,是无解的。如果不够,可以增加worker数量,但这显然会增加系统开销。worker数量的选择最好与机器的cpu数量一致,因为在locust源码中,worker与worker之间是进程级别,而python会默认把进程尽可能多的分开给cpu,这也可以尽可能多的利用机器资源。
linux就没有这个问题,在linux系统中可以去设置系统句柄限制。普遍来说linux作为压测机比windows性能要好的多。
另一个值得注意的问题则是,在htpp请求中,不同的请求内部会消耗掉不同的端口号(发送端不是接收端,接收端是固定的)。http请求底层是基于tcp的,每次http请求都会经过:建立连接-发送-接收-释放连接,而tcp的设置会决定释放连接的时效问题。如果释放不及时,压测时候同一时间有大量端口占用就可能导致后续请求没有端口了。windows的端口数量最多只有6万多个(这还得在注册表去设置),假设一个连接占用端口时间为3s,那么理论上来讲每秒2万rps就是这台机器的上限了。所以我们这块需要去注册表设置tcp和端口,可参考https://www.jianshu.com/p/00136a97d2d8。