在介绍FastHttpUser之前,我们先看一下,Locust默认客户端使用的是啥?
Locust 默认客户端使用的是python-requests。
>> 如果不了解 python-requests,可以看一下小鱼的这篇:《requests库常用到的7个主要方法及控制访问参数》
或者官方文档,如果有足够耐心的话:《Requests》
我们接着说,使用requests是Pyhton维护非常方便的包,并且在python应用中非常广泛,栗如:爬虫,接口等。
所以,官网是非常推荐我们使用HttpUser。
但是,如果我们的测试规模非常大,数据量非常大,那么这个时候,我们就可以使用 Http客户端,该客户端使用的是geventhttpclient 而不是请求,好处呢,就是进行HTTP请求的性能提高了5~6倍,是不是很厉(尿)害(性) !!!
注:
1、提高 5~6倍,这并不意味着每个CPU内核可以模拟的用户数量将自动增加到5至6倍,因为这不去取决于负载测试脚本的其他功能;
2、如果locust脚本在执行HTTP请求时花费大量的CPU时间,那么将会得到显著的性能提升!
1、geventhttpclient专门为高并发、流传输和支持HTTP 1.1持久连接而设计。
2、它旨在有效地从REST API和Twitter之类的流API中提取信息。
3、默认情况下,提供SSL支持。
>>>① geventhttpclient取决于证书CA Bundle。
>>>② 这是与Requests代码库一起提供的相同的CA Bundle,它是从Mozilla Firefox的规范集衍生而来的。
4、支持Python 2.7和Python 3.4+。不再支持Python 2.6。
注:
官方不建议将SSL / TLS与python 2.7.9一起使用。
很简答的一段代码,就是通过geventhttpclient 来获取 请求,响应信息,状态码等数据。
老规矩,上代码
# -*- coding:utf-8 -*- # @Time : 2022-05-28 # @Author : Carl_奕然 from geventhttpclient import HTTPClient from geventhttpclient.url import URL url = URL('http://baidu.com') http =HTTPClient(url.host) #获取一个请求 response = http.get(url.request_uri) #读取状态码 response.status_code #读取返回内容 body = response.read() #关闭链接 http.close()
HTTPClient具有内置的连接池,可以在多个并发线程中使用同一个实例。
上代码,
# -*- coding:utf-8 -*- # @Time : 2022-05-28 # @Author : Carl_奕然 import gevent.pool import json from geventhttpclient import HTTPClient from geventhttpclient.url import URL #获取某网站的token Token = '<go to http://developers.xxx.com/tools/explorer and copy the access token>' url = URL('https://xxx.com/me/friends') url['access_token'] = Token #设置 10个并发和10和连接数 http = HTTPClient.from_url(url,concurrency =10) #设置响应请求 response = http.get(url.request_uri) #抛出 状态 assert response.status_code == 200 #将读取的信息流,传递到json解析器中 data = json.loads(response)['data'] #定义方法,来打印friend_username def print_friend_username(http,friend_id): #设置 http,friend_id 两个参数 #url地址拼接 fiend_url = URL('/'+str(friend_id)) fiend_url['access_token'] = Token #在链接之前,线程会处于阻塞状态 response = http.get(fiend_url.request_uri) assert response.status_code ==200 friend = json.load(response) #判断是否存在username if friend.has_key('username'): print (f"{firend['username']} :{friend['name']}") else: print(f"{friend['name'] has no username}") #设置一次运行20个线程 pool = gevent.pool.Pool(20) #循环读取 for item in data: friend_id = item['id'] pool.spawn(print_friend_username,http,friend_id) pool.json() #关闭 http.close()
这里小鱼在强调几点:
1、信息最好是使用json解析器,快捷方便;
2、线程数根据自己是实际业务量来编写;
3、每次执行完,在最后,需要关闭http,不然耗资源。
4、小鱼自认为,注释还算明白,不明白的,可要补基础知识了!
geventhttpclient支持流,这是一大特色,
响应状态具有:read(),readline()方法,他们都是以增量的方式读取。
我们来个例子,看看牛在啥地方
# -*- coding:utf-8 -*- # @Time : 2022-05-28 # @Author : Carl_奕然 from geventhttpclient import HTTPClient from geventhttpclient.url import URL #本地的文件地址 url = URL('http://127.0.0.1:80/100.dat') #获取请求 http = HTTPClient.from_url(url) #获取响应信息 response = http.get(url.query_string) #抛出200的说明OK的 assert response.status_code == 200 #文件的大小 CHUNK_SIZE = 1024 * 16 # 16KB #with方法打开文件 with open('/data/100.dat', 'w') as f: while data: f.write(data) data = response.read(CHUNK_SIZE)
小屌丝:鱼哥,这不就是一个下载大文件的方法吗?
小鱼:是啊,
小屌丝:那这有啥稀奇的,我到没看出来啥道道。
小鱼:那你知道,下载大文件的方法那么多,我为啥偏偏喜欢用 gevent 来下载?
小屌丝:因为你现在不就是在讲 geventhttpclient嘛!(很装叉的样子)
小鱼:还有呢??
小屌丝:额…
小鱼:因为 使用geventhttpclient ,可以节省内存啊 !!!!
小屌丝:挖草~ 这也可以!!
我们直接上代码,
在代码中,理解如何使用
# -*- coding:utf-8 -*- # @Time : 2022-05-28 # @Author : Carl_奕然 from locust import task,between from locust.contrib.fasthttp import FastHttpUser class MyUser(FastHttpUser): #设置时间间隔在 1~5秒之间 wite_time = (1,5) @task def index(self): response = self.client.get("/")
看到没有,就是这么简单,
如果没理解@task的用法,可以参照小鱼的上一篇文章,
《深聊性能测试,从入门到放弃之:Locust性能自动化(二)代码实战》
这里有详细介绍 @task的用法,在本篇不多阐述。
注:
因为 FastHttpUser 使用的是不同的客户端(geventhttpclient)及API来实现,所以, 并不总能代替HttpUser,但是偶尔可以代替一下!!!!
刚刚小鱼也提到了, FastHttpUser与HttpUser(python-requests)相比,
使用的是 (geventhttpclient) 这个客户端,所以:
① 速度比HttpUser 快;
②功能比HttpUser 弱。
由于该用户的行为由其任务定义,可以通过使用 @task decorator 方法或通过设置来直接在类上声明 ,takss attribute。
此类在实例化时创建一个客户端属性,该属性是一个HTTPClient,支持在请求之间保持用户会话。
接下来,详细看一下:
1、定义FastHttpUser 类
#定义FastHttpUser 类 class FastHttpUser(environment)
2、参数及定义
# 传递给FastHttpSession的参数 connection_timeout: float= 60.0 #参数传递给FastHttpSession。默认值为True,表示不进行SSL验证。 insecure: bool= True #参数传递给FastHttpSession。默认值5,表示4次重定向。 max_retries: int= 1 #参数传递给FastHttpSession。默认值1,表示零重试。 max_redirects: int= 5 #传递给FastHttpSession的参数 network_timeout: float= 60.0
关于 FastHttpSession类的内容,我们直接代码中解析:
1、定义FastHttpSession 类
#定义FastHttpSession 类 class FastHttpUser(environment,base_url,insecure = True,** kwargs)
2、参数及定义
# 发送get请求 get(Path,**kwargs) # 发送head请求 head(Path,**kwargs) # 发送option请求 option(Path,**kwargs) # 发送patch请求 patch(Path,data = None,**kwargs) # 发送post请求 post(Path,data = None,**kwargs) # 发送put请求 put(Path,data = None,**kwargs) #发送http请求并返回loucst.contrib.fasthttp.FastResponse 对象 request(method, path, name=None, data=None, catch_response=False, stream=False, headers=None, auth=None, json=None, allow_redirects=True, **kwargs)
这里我们单独解析一下 request方法里面的参数:
①method: 新的request 方法;
②path:请求主机地址,url;
③name:可选参数,可以指定为在Locust的统计信息中用作标签,而不是URL路径;
④data:可选参数,要在请求正文中发送的字符串/字节;
⑤catch_response:可选参数,如果已设置,则可用于发出请求,以返回上下文管理器以用作with语句的参数。可自行进行标记,例如200可以设置Success,也可以设置成Fail。
⑥stream:可选参数,
>>>>如果设置成Ture,则不会立即使用响应主体,而是可以通过访问Response对象上的stream属性来使用它;
>>>>如果设置成False,在Locust报告的请求时间中不会考虑下载响应内容的时间。
⑦headers:与请求一起发送的HTTP headers字典;
⑧auth:可选参数,身份认证(用户名、密码等);
⑨json:可选参数,在请求正文中发送的字典。
1、定义FastResponse 类
#定义FastResponse 类 classFastResponse(ghc_response, request=None, sent_request=None)
2、参数及定义
① content属性:
必要时解压缩并缓冲接收到的正文。注意大文件的情况!
②headers:
包含响应标头的类对象字典;
③json():
将响应解析为json并返回一个dict;
④text属性:
以解码的字符串形式返回响应的文本内容。