前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >性能测试工具locust源码分析

性能测试工具locust源码分析

原创
作者头像
历久尝新
发布2021-04-22 11:37:25
1.7K0
发布2021-04-22 11:37:25
举报
文章被收录于专栏:学而时习之学而时习之

1. 背景

目前接触以及听说过的压测工具/框架繁多,如jmeter/k6/locust/loadrunner/qload等,每个压测工具都有自己特性和不足,如何选择适合自己的压测工具,简单高效的完成自己的压测目标,是我们应该思考的问题,本文旨在对locust的特性以及实现进行梳理,方便并对qload以及jmeter进行一个简单的横向对比。

locust工具地址:https://github.com/locustio/locust/

locust官方文档:https://locust.io/

2. 特性

  1. 基于python,requests,zeromq(分布式),coroutine(高并发)的开源(支持二次开发)压测工具;
  2. 压力实现方式为模拟用户操作+gevent实现并发;
  3. 设计简单优雅,模块间耦合低,为使用者的二次开发拓展提供极大的便利;
  4. 支持多场景多协议压测,如restapi/redis/mysql等等,原生支持对http协议的压测;
  5. 支持定制化结果展示,locust默认使用flask后台上报到原生的web前端,可定制使用es+kibana/prometheus+grafana等;
  6. 支持多平台,locust-master+boomer-salve的分布式方式提高并发。

3. 使用

支持单机/分布式执行压测,由于python 受限于GIL,导致locust高并发下一言难尽,想要发挥单机性能可选用单机主从的分布式方式执行压测,若还不能满足压力要求可进一步增加执行机节点,采用一主错从的方式,甚至可拓展使用boomer来进一步发挥执行机性能。

脚本编写:

脚本locustfile.py
脚本locustfile.py

3.1单机

locust -f locustfile.py

3.2 单机主从

locust -f locustfile.py --master

locust -f locustfile.py --woker

3.3 多机主从

locust -f locustfile.py --master

locust -f locustfile.py --woker --master-host=192.168.x.xx

4. 实现

实现与qload较为相似,都采用了模拟用户操作+gevent+节点结果采集上报的方式实现生产压力和结果收集。

4.1 架构

locust与qload架构图如下:

qload&&locust架构图
qload&&locust架构图
  • qload与locust架构相似,qload借助QTA的分布式能力,将任务下发到执行机,locust采用master-salve的方式,借助zeroMQ,在压测准备阶段,指定节点的角色;
  • master与slave之间使用pyzmq(zeromq的python实现)建立一对多的连接;
  • 通过节点采集器通过flask上报到前端,原生的结果展示较为简单且无法保存,往往我需要自己定制结果展示;

4.2 依赖

依赖
依赖
  • gevent:python协程库,给locust提供并发能力;
  • requests:发送http请求,locust重新封装;
  • flask:web框架,给locust的压测页面提供后台服务;
  • pyzmq+msgpack:做分布式的消息通信。

4.3 模块

从核心代码中看locust原生实现

核心类
核心类

4.3.1 用例模块

类似qload,通过vu来定义各种协议以及动作权重等。

  • User:压测所需要的“用户”,用户的行为由其属性以及方法定义,这个类通常由真正客户端需要的用户类来继承,如HttpUser,实现了支持http协议的客户端用户;
  • HttpUser:压测所需要可产生http请求的“用户”,继承于User类,这个类在实例时会创建一个client,用于在请求之间保持用户会话;
  • HttpSession:为HttpUser的实例提供client,继承于requests.Session,用于执行http请求和在请求之间保存状态,并且使用上下文管理器的方式定制返回的结果,每个请求都会被记录,用于locust的结果展示;
  • TaskSet:定义“任务”组,被“用户”所执行,且TaskSet可以嵌套(支持套娃),可以分配权重,执行时间由定义“用户”的User类的wait_time属性决定。

4.3.2 控制模块

locust/runners.py
locust/runners.py
  • Runner:通过启停和编排“用户”来进行压测,是DistributedRunner的基类;
  • DistributedRunner:和Runner基本一样,但是进行了一系列事件监听的注册,用于测试结果的上报,监听在3.3.5事件钩子中会分析;
  • MasterRunner:master节点的Runner核心,本身不会产生任何greenlets,但会与WokerRunner进行连接,控制启停greenlets,并将WokerRunner产生的压力结果进行聚合;
  • WokerRunner:salve节点的Runner核心,会与MasterRunner进行连接,被master控制的启停“用户”greenlets,并定期将“用户”生成的数据统计,并上报至WokerRunner。

Runner中的state属性记录节点的状态,master与slave共有7种状态

locust/runners.py:28
locust/runners.py:28

Runner的状态虽然不多,但实现了master和salve之间的状态同步,控制了压测的启停,注:下图中hatching在最新的locust版本中,由spaning代替

执行状态
执行状态
  • ready:准备就绪,master和salve启动后默认状态;
  • spawning:正在准备压力机,master通知salve准备启动压测,salve过渡到running的一个状态;
  • running:执行压测;
  • cleanup:执行stopping前的一个状态;
  • stopping:正在通知各个salve停止压测;
  • stopped:压测已停止;
  • missing:状态丢失,master3s没有收到salve就会默认为missing;

4.3.3 通信模块

提供m-s之间的通信能力,封装了zeromq

locust/rpc
locust/rpc
  • BaseSocket:socket基类,封装了zeromq,提供了1:N特性,每个master与salve之间各维持一个tcp连接,提供master命令下发和salve信息上报能力;
  • Server:继承BaseSocket,作为压测系统的Server端;
  • Clint:继承BaseSocket,作为压测系统的Client端;
  • Message:消息的封装,序列化与反序列化,数据是通过WorkerRunner的stats_report上报;

master和salve之间通信的消息类型,共10种,salve发送至master的8种,master发送至slave的3种:

locust/runners.py:626
locust/runners.py:626
locust/runners.py:771
locust/runners.py:771
  • spawn:只有master发送,开始执行;
  • stop:只有master发送,点击停止;
  • quit:退出包括异常退出;
  • client_ready:salve启动后和压测停止;
  • client_stopped:压测完成并发停止后;
  • heartbeat:心跳,3s一次;
  • stats:压测信息,3s一次;
  • spawning:用户准备过程中;
  • spawning_complete:用户数据集分配等完成;
  • exception:user执行过程中出现error;

4.3.4 统计模块

结果采集/分析,定义数据上报格式等,在master和slave通信中的stats的消息类型,作用是salve给master发送的消息,默认3s上报一次,stats中的数据从哪里来?又存储在什么样的对象中?发送给master后,进行怎样的聚合?

locust.stats
locust.stats
  • RequestStats:该类保存请求统计信息 locust/stats.py:187
    • 在每一个locust实例中(无论是master还是salve),RequestStats都是单例,包含了单个salve汇总的信息,以及各个请求url或或name的统计信息,在分布式下,每一个salve都会维护一个RequestStats实例,3s周期通过stats_reporter方法将信息发送到master,上报的方式在DistributedRunner实例时通过调用setup_distributed_stats_event_listeners方法,用事件钩子方式进行注册监听,发送完后salve runner的stats会调用reset_all方法进行重置;
    • self.total :StatsEntry实例,记录成功率,失败率等等,对于master来说,每3s的周期就会调用extend方法进行累加,周期的调用方法也是通过setup_distributed_stats_event_listeners方法;
    • self.entities:字典,key为(name, method),value为StatsEntry实例;
    • self.errors:字典,key为name+method+error封装的哈希值,value为StatsError实例;
  • StatsEntry:表示单个统计项(名称和方法) locust/stats.py:614
    • 实际上报的数据如下:
locust.stats.StatsEntry.serialize
locust.stats.StatsEntry.serialize

StatsError:统计错误信息 locust/stats.py:671

代码语言:txt
复制
- 实际上报的数据如下:
locust.stats.StatsError.to_dict
locust.stats.StatsError.to_dict

4.3.5 事件钩子

locust/event.py
locust/event.py
  • EventHook:给locust不同类型的事件提供钩子
locust/event.py
locust/event.py

Events:事件集合

代码语言:txt
复制
- 原生支持11种事件
locust/event.py
locust/event.py

钩子实现原理

定义处理函数 --> add_lisener注册到eventhook --> 触发执行eventhook -->hook的fire 遍历执行处理函数

  • 定义处理函数并注册:
locust/stats.py:692
locust/stats.py:692
  • 触发执行eventhook:
locust/runners.py:812
locust/runners.py:812
  • hook遍历并执行处理函数:
locust/event.py:33
locust/event.py:33

钩子的使用方式,原生eg:

1. 常规方式

locust.stats.setup_distributed_stats_event_listeners
locust.stats.setup_distributed_stats_event_listeners

2. 使用装饰器

examples.extend_web_ui.extend.on_request_success
examples.extend_web_ui.extend.on_request_success

5. 对比

便捷度:jemter > qload > locust

工具栈:jemter > locust/qload

并发能力:locust(boomer) > qload > jemter

可拓展性:locust > qload > jemter

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 背景
  • 2. 特性
  • 3. 使用
    • 脚本编写:
      • 3.1单机
        • 3.2 单机主从
          • 3.3 多机主从
          • 4. 实现
            • 4.1 架构
              • 4.2 依赖
                • 4.3 模块
                  • 4.3.1 用例模块
                  • 4.3.2 控制模块
                  • 4.3.3 通信模块
                  • 4.3.4 统计模块
                  • 4.3.5 事件钩子
                  • 1. 常规方式
                  • 2. 使用装饰器
              • 5. 对比
              相关产品与服务
              Grafana 服务
              Grafana 服务(TencentCloud Managed Service for Grafana,TCMG)是腾讯云基于社区广受欢迎的开源可视化项目 Grafana ,并与 Grafana Lab 合作开发的托管服务。TCMG 为您提供安全、免运维 Grafana 的能力,内建腾讯云多种数据源插件,如 Prometheus 监控服务、容器服务、日志服务 、Graphite 和 InfluxDB 等,最终实现数据的统一可视化。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档