locust压测环境描述

本文环境python3.5.2
locust版本0.9.0

locust示例的执行过程

上文大概描述了locust的启动了流程,本文主要是接着上文继续分析,示例代码中的http的测试的执行过程,是如何去访问远端的http接口的流程。接着就分析如何通过传入的运行时间参数来停止locust的运行。

http测试用例的执行

示例代码中访问url的代码如下:

@task(2)
def index(self):self.client.get("/")@task(1)
def profile(self):self.client.get("/profile")

其中的client就是继承自HttpLocust初始化过程中创建的,由于示例代码里面的WebsiteUser继承自HttpLocust,在初始化的过程的时候;

class HttpLocust(Locust):"""Represents an HTTP "user" which is to be hatched and attack the system that is to be load tested.The behaviour of this user is defined by the task_set attribute, which should point to a :py:class:`TaskSet <locust.core.TaskSet>` class.This class creates a *client* attribute on instantiation which is an HTTP client with support for keeping a user session between requests."""client = None"""Instance of HttpSession that is created upon instantiation of Locust. The client support cookies, and therefore keeps the session between HTTP requests."""def __init__(self):super(HttpLocust, self).__init__()if self.host is None:raise LocustError("You must specify the base host. Either in the host attribute in the Locust class, or on the command line using the --host option.")self.client = HttpSession(base_url=self.host)               # 初始化一个client实例

此时的client就是一个HttpSession的实例,分析该类:

class HttpSession(requests.Session):                                    # 继承自requests.Session"""Class for performing web requests and holding (session-) cookies between requests (in orderto be able to log in and out of websites). Each request is logged so that locust can display statistics.This is a slightly extended version of `python-request <http://python-requests.org>`_'s:py:class:`requests.Session` class and mostly this class works exactly the same. However the methods for making requests (get, post, delete, put, head, options, patch, request) can now take a *url* argument that's only the path part of the URL, in which case the host part of the URL will be prepended with the HttpSession.base_url which is normally inheritedfrom a Locust class' host property.Each of the methods for making requests also takes two additional optional arguments which are Locust specific and doesn't exist in python-requests. These are::param name: (optional) An argument that can be specified to use as label in Locust's statistics instead of the URL path. This can be used to group different URL's that are requested into a single entry in Locust's statistics.:param catch_response: (optional) Boolean argument that, if set, can be used to make a request return a context manager to work as argument to a with statement. This will allow the request to be marked as a fail based on the content of the response, even if the response code is ok (2xx). The opposite also works, one can use catch_response to catch a requestand then mark it as successful even if the response code was not (i.e 500 or 404)."""def __init__(self, base_url, *args, **kwargs):super(HttpSession, self).__init__(*args, **kwargs)                                  # 调用父类的初始化方法self.base_url = base_url                                                            # 设置Host# Check for basic authenticationparsed_url = urlparse(self.base_url)                                                # 解析urlif parsed_url.username and parsed_url.password:                                     # 检查是否配置了用户名与密码netloc = parsed_url.hostnameif parsed_url.port:netloc += ":%d" % parsed_url.port# remove username and password from the base_urlself.base_url = urlunparse((parsed_url.scheme, netloc, parsed_url.path, parsed_url.params, parsed_url.query, parsed_url.fragment))# configure requests to use basic authself.auth = HTTPBasicAuth(parsed_url.username, parsed_url.password)def _build_url(self, path):""" prepend url with hostname unless it's already an absolute URL """if absolute_http_url_regexp.match(path):                                            # 检查是否是绝对路径return path                                                                     # 如果是绝对路径则直接返回else:return "%s%s" % (self.base_url, path)                                           # 返回完整的urldef request(self, method, url, name=None, catch_response=False, **kwargs):"""Constructs and sends a :py:class:`requests.Request`.Returns :py:class:`requests.Response` object.:param method: method for the new :class:`Request` object.:param url: URL for the new :class:`Request` object.:param name: (optional) An argument that can be specified to use as label in Locust's statistics instead of the URL path. This can be used to group different URL's that are requested into a single entry in Locust's statistics.:param catch_response: (optional) Boolean argument that, if set, can be used to make a request return a context manager to work as argument to a with statement. This will allow the request to be marked as a fail based on the content of the response, even if the response code is ok (2xx). The opposite also works, one can use catch_response to catch a requestand then mark it as successful even if the response code was not (i.e 500 or 404).:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.:param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`.:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.:param files: (optional) Dictionary of ``'filename': file-like-objects`` for multipart encoding upload.:param auth: (optional) Auth tuple or callable to enable Basic/Digest/Custom HTTP Auth.:param timeout: (optional) How long in seconds to wait for the server to send data before giving up, as a float, or a (`connect timeout, read timeout <user/advanced.html#timeouts>`_) tuple.:type timeout: float or tuple:param allow_redirects: (optional) Set to True by default.:type allow_redirects: bool:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.:param stream: (optional) whether to immediately download the response content. Defaults to ``False``.:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair."""# prepend url with hostname unless it's already an absolute URLurl = self._build_url(url)                                                                  # 获取访问路径# store meta data that is used when reporting the request to locust's statisticsrequest_meta = {}                                                                           # 请求头部信息# set up pre_request hook for attaching meta data to the request objectrequest_meta["method"] = method                                                             # 请求的方法request_meta["start_time"] = time.time()                                                    # 请求开始的时间response = self._send_request_safe_mode(method, url, **kwargs)                              # 访问请求并获取返回值# record the consumed timerequest_meta["response_time"] = (time.time() - request_meta["start_time"]) * 1000           # 记录响应处理的时间request_meta["name"] = name or (response.history and response.history[0] or response).request.path_url# get the length of the content, but if the argument stream is set to True, we take# the size from the content-length header, in order to not trigger fetching of the bodyif kwargs.get("stream", False):request_meta["content_size"] = int(response.headers.get("content-length") or 0)         # 获取返回的文件长度else:request_meta["content_size"] = len(response.content or b"")                             # 否则获取响应的整体大小if catch_response:                                                                          # 如果要包含请求信息response.locust_request_meta = request_meta return ResponseContextManager(response)                                                 # 用ResponseContextManager包裹responseelse:try:response.raise_for_status()                                                         # 检查返回状态except RequestException as e:events.request_failure.fire(request_type=request_meta["method"], name=request_meta["name"], response_time=request_meta["response_time"], exception=e, )                                                                                   # 如果失败则通知所有的失败请求事件执行else:events.request_success.fire(request_type=request_meta["method"],name=request_meta["name"],response_time=request_meta["response_time"],response_length=request_meta["content_size"],)                                                                                   # 如果成功则通知所有的成功事件执行return responsedef _send_request_safe_mode(self, method, url, **kwargs):"""Send an HTTP request, and catch any exception that might occur due to connection problems.Safe mode has been removed from requests 1.x."""try:return requests.Session.request(self, method, url, **kwargs)                # 调用requests的Session去请求接口except (MissingSchema, InvalidSchema, InvalidURL):raiseexcept RequestException as e:r = LocustResponse()r.error = er.status_code = 0  # with this status_code, content returns Noner.request = Request(method, url).prepare() return r

由该代码可知,处理的请求都是通过requests库中的Session来进行请求的,示例代码中的client都是通过requests的代码进行请求,并且还可以使用session来保持会话,从而使接口请求的时候能够带上权限检查等额外信息。

locust定时退出

由于可以在启动locust可以指定执行的时间,可以到时间退出,我们分析一下该退出函数的执行,

    def spawn_run_time_limit_greenlet():logger.info("Run time limit set to %s seconds" % options.run_time)def timelimit_stop():logger.info("Time limit reached. Stopping Locust.")runners.locust_runner.quit()gevent.spawn_later(options.run_time, timelimit_stop)

等到了run_time之后,就会执行timelimit_stop函数,而该函数就是调用了实例化的locust类实例的quit方法;

def stop(self):# if we are currently hatching locusts we need to kill the hatching greenlet firstif self.hatching_greenlet and not self.hatching_greenlet.ready():       # 检查是否有hatch_greenlet并且没有准备好 就杀掉该协程self.hatching_greenlet.kill(block=True)self.locusts.kill(block=True)                                           # 杀死所有的协程组self.state = STATE_STOPPED                                              # 更改状态为停止态events.locust_stop_hatching.fire()                                      # 通知所有locust_stop_hatching的函数执行def quit(self):self.stop()                                                             # 停止执行所有的greenletself.greenlet.kill(block=True)                                          # 主greenlet杀死

此时就是停止所有的协程执行,终止该测试用例的执行。其中events.locust_stop_hatching使用了典型的观察者设计模式:

locust_stop_hatching = EventHook()class EventHook(object):"""Simple event class used to provide hooks for different types of events in Locust.Here's how to use the EventHook class::my_event = EventHook()def on_my_event(a, b, **kw):print "Event was fired with arguments: %s, %s" % (a, b)my_event += on_my_eventmy_event.fire(a="foo", b="bar")If reverse is True, then the handlers will run in the reverse orderthat they were inserted"""def __init__(self):self._handlers = []                                         # 所有待处理的handlersdef __iadd__(self, handler):self._handlers.append(handler)                              # 添加到处理的Handler列表中return selfdef __isub__(self, handler):self._handlers.remove(handler)                              # 移除handlerreturn selfdef fire(self, reverse=False, **kwargs):if reverse:self._handlers.reverse()                                # 是否排序for handler in self._handlers:                              # 依次遍历handler并执行handler(**kwargs)

总结

本文主要是继续分析了locust启动之后,http的请求的处理与定时退出的功能,其中http的请求都是基于requests.Session来实现的,定时退出的功能主要还是依赖于gevent中的Group来控制所有已经运行的协程,通过停止所有运行的协程来达到关闭停止运行的目的,其中还有些许细节并没有详细说明,大家有兴趣可自行查阅相关源码。鉴于本人才疏学浅,如有疏漏请批评指正

locust压测工具:http测试过程与定时停止相关推荐

  1. locust压测工具:启动概述

    locust压测工具启动概述 本文环境python3.5.2 locust版本0.9.0 locust概述 locust是一个简单易用.分布式的用户压测工具,并确定系统可以处理多少并发用户.在测试的时 ...

  2. locust压测工具【学习】

    locust压测工具[学习] 1.安装:pip3 install locust 检验版本:locust -V 2.使用脚本: from locust import task, HttpUser, co ...

  3. locust压测工具:测试信息输出与分布式模式

    locust压测环境描述 本文环境python3.5.2 locust版本0.9.0 locust测试信息输出与分布式模式 本文将主要分析两个方面的内容: 1.locust在启动运行在跑测试用例的时候 ...

  4. 基于python的压测工具_Python Locust性能测试简介及框架实践

    Locust(俗称 蝗虫), 一个轻量级的开源压测工具,用Python编写.使用 Python 代码定义用户行为,也可以仿真百万个用户: Locust 非常简单易用,是分布式,用户负载测试工具.Loc ...

  5. 压测工具之Locust

    前言   说起压测,我就用过Jmeter,而且仅是简单使用,好用性能强大,最近接触了一个python提供的压测框架Locust,翻译为蝗虫,蝗虫过之,寸草不生,哈哈哈,我感觉很贴切. 首先,我们分析一 ...

  6. Http压测工具wrk使用指南【转】

    用过了很多压测工具,却一直没找到中意的那款.最近试了wrk感觉不错,写下这份使用指南给自己备忘用,如果能帮到你,那也很好. 安装 wrk支持大多数类UNIX系统,不支持windows.需要操作系统支持 ...

  7. Http压测工具wrk使用指南

    用过了很多压测工具,却一直没找到中意的那款.最近试了wrk感觉不错,写下这份使用指南给自己备忘用,如果能帮到你,那也很好. 安装 wrk支持大多数类UNIX系统,不支持windows.需要操作系统支持 ...

  8. web压测工具http_load原理分析

    一.前言 http_load是一款测试web服务器性能的开源工具,从下面的网址可以下载到最新版本的http_load: http://www.acme.com/software/http_load/  ...

  9. 【腾讯优测干货分享】从压测工具谈并发、压力、吞吐量

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/580d914e07b7fc1c26a0cf7c 前言 随着部门业务的拓展,我们有 ...

最新文章

  1. php arraymap()函数
  2. leetcode算法题-- 最长递增子序列的个数★
  3. 手写select,解决浏览器兼容性
  4. python 如何将字符串列表合并后转换成字符串? ''.join(List(str))函数
  5. boost::hana::flip用法的测试程序
  6. iPhone13真香了?苹果官网被抢崩了,连夜补货!粉色或成爆款..
  7. Jtopo Demo源码下载方式
  8. 微软在Windows 8之后将放弃Windows品牌
  9. Python 调用IDM下载器
  10. vb.net 教程 5-19 拓展:制作一个QQ大家来找茬和美女找茬辅助工具
  11. uniapp实现复制功能
  12. 计算机专业知识教学,2016计算机专业知识:计算机的分类(一)
  13. 判断三维空间两线段是否相交(附代码)
  14. CPU中寄存器作用及说明
  15. graphql入门使用-查询
  16. 惠普台式计算机配置,hp惠普台式机bios设置图文教程
  17. Java之国际化操作
  18. QQ游戏图标熄灭大全
  19. 如何使用计算机查看IP以及修改IP,查看自己电脑IP和更改自己电脑MAC地址
  20. python毒酒检测_Turkey HSD检验法/W法

热门文章

  1. 英特尔发布智慧社区解决方案,全栈技术支撑,涵盖五大战略方向
  2. 从数百个Excel中查找数据,一分钟用Python搞定
  3. 今晚 8 点直播 | OpenCV 20 年,首款开源软硬一体的 OAK 套件来了!
  4. 用 Python 可以实现侧脸转正脸?我也要试一下!
  5. 训练数据也外包?这家公司“承包”了不少注释训练数据,原来是这样做的……...
  6. 囚犯学会编程之后会发生什么?
  7. 假设检验怎么做?这次把方法+Python代码一并教给你
  8. 阿里深度序列匹配模型SDM:如何刻画大型推荐系统的用户行为?
  9. 面试官:聊一聊 Spring Boot 服务监控机制
  10. 万万没想到! logger.info() 还能导致线上故障?