使用Python的Treq on Twisted来进行HTTP压力测试


Posted in Python onApril 16, 2015

从事API相关的工作很有挑战性,在高峰期保持系统的稳定及健壮性就是其中之一,这也是我们在Mailgun做很多压力测试的原因。

这么久以来,我们已经尝试了很多种方法,从简单的ApacheBench到复杂些的自定义测试套。但是本贴讲述的,是一种使用python进行“快速粗糙”却非常灵活的压力测试的方法。
使用python写HTTP客户端的时候,我们都很喜欢用 Requests library。这也是我们向我们的API用户们推荐的。Requests 很强大,但有一个缺点,它是一个模块化的每线程一个调用的东西,很难或者说不可能用它来快速的产生成千上万级别的请求。
Treq on Twisted简介

为解决这个问题我们引入了Treq (Github库)。Treq是一个HTTP客户端库,受Requests影响,但是它运行在Twisted上,具有Twisted典型的强大能力:处理网络I/O时它是异步且高度并发的方式。

Treq并不仅仅限于压力测试:它是写高并发HTTP客户端的好工具,比如网页抓取。Treq很优雅、易于使用且强大。这是一个例子:

>>> from treq import get
  
 >>> def done(response):
 ...   print response.code
 ...   reactor.stop()
  
 >>> get("http://www.github.com").addCallback(done)
  
 >>> from twisted.internet import reactor
 200

简单的测试脚本
如下是一个使用Treq的简单脚本,用最大可能量的请求来对单一URL进行轰炸。

#!/usr/bin/env python
 from twisted.internet import epollreactor
 epollreactor.install()
  
 from twisted.internet import reactor, task
 from twisted.web.client import HTTPConnectionPool
 import treq
 import random
 from datetime import datetime
  
 req_generated = 0
 req_made = 0
 req_done = 0
  
 cooperator = task.Cooperator()
  
 pool = HTTPConnectionPool(reactor)
  
 def counter():
   '''This function gets called once a second and prints the progress at one
   second intervals.
   '''
   print("Requests: {} generated; {} made; {} done".format(
       req_generated, req_made, req_done))
   # reset the counters and reschedule ourselves
   req_generated = req_made = req_done = 0
   reactor.callLater(1, counter)
  
 def body_received(body):
   global req_done
   req_done += 1
  
 def request_done(response):
   global req_made
   deferred = treq.json_content(response)
   req_made += 1
   deferred.addCallback(body_received)
   deferred.addErrback(lambda x: None) # ignore errors
   return deferred
  
 def request():
   deferred = treq.post('http://api.host/v2/loadtest/messages',
              auth=('api', 'api-key'),
              data={'from': 'Loadtest <test@example.com>',
                 'to': 'to@example.org',
                'subject': "test"},
             pool=pool)
   deferred.addCallback(request_done)
   return deferred
  
 def requests_generator():
   global req_generated
   while True:
     deferred = request()
     req_generated += 1
     # do not yield deferred here so cooperator won't pause until
     # response is received
     yield None
  
 if __name__ == '__main__':
   # make cooperator work on spawning requests
   cooperator.cooperate(requests_generator())
  
   # run the counter that will be reporting sending speed once a second
   reactor.callLater(1, counter)
  
   # run the reactor
   reactor.run()

输出结果:

2013-04-25 09:30 Requests: 327 generated; 153 sent; 153 received
 2013-04-25 09:30 Requests: 306 generated; 156 sent; 156 received
 2013-04-25 09:30 Requests: 318 generated; 184 sent; 154 received

“Generated”类的数字代表被Twisted反应器准备好但是还没有发送的请求。这个脚本为了简洁性忽略了所有错误处理。为它添加超时状态的信息就留给读者作为一个练习。

这个脚本可以当做是一个起始点,你可以通过拓展改进它来自定义特定应用下的处理逻辑。建议你在改进的时候用collections.Counter 来替代丑陋的全局变量。这个脚本运行在单线程上,想通过一台机器压榨出最大量的请求的话,你可以用类似 mulitprocessing 的技术手段。

愿你乐在压力测试!

Python 相关文章推荐
python从入门到精通(DAY 1)
Dec 20 Python
python相似模块用例
Mar 04 Python
python+opencv实现动态物体追踪
Jan 09 Python
python3.5+tesseract+adb实现西瓜视频或头脑王者辅助答题
Jan 17 Python
python 统计列表中不同元素的数量方法
Jun 29 Python
Python get获取页面cookie代码实例
Sep 12 Python
python中退出多层循环的方法
Nov 27 Python
python Django里CSRF 对应策略详解
Aug 05 Python
浅谈Python的方法解析顺序(MRO)
Mar 05 Python
Python3批量创建Crowd用户并分配组
May 20 Python
python3中for循环踩过的坑记录
Dec 14 Python
Python词云的正确实现方法实例
May 08 Python
Python3中多线程编程的队列运作示例
Apr 16 #Python
使用Python脚本操作MongoDB的教程
Apr 16 #Python
使用Python中的greenlet包实现并发编程的入门教程
Apr 16 #Python
利用Python的Twisted框架实现webshell密码扫描器的教程
Apr 16 #Python
使用Python的Twisted框架实现一个简单的服务器
Apr 16 #Python
使用Python的Twisted框架编写简单的网络客户端
Apr 16 #Python
从Python的源码浅要剖析Python的内存管理
Apr 16 #Python
You might like
PHP分页详细讲解(有实例)
2013/10/30 PHP
PHP安全的URL字符串base64编码和解码
2014/06/19 PHP
php实现根据词频生成tag云的方法
2015/04/17 PHP
php创建无限级树型菜单
2015/11/05 PHP
Laravel中如何增加自定义全局函数详解
2017/05/09 PHP
拖动Html元素集合 Drag and Drop any item
2006/12/22 Javascript
查询绑定数据岛的表格中的文本并修改显示方式的js代码
2009/12/15 Javascript
window.print打印指定div实例代码
2013/12/13 Javascript
在JavaScript中重写jQuery对象的方法实例教程
2014/08/25 Javascript
javascript中定义类的方法详解
2015/02/10 Javascript
基于jQuery实现二级下拉菜单效果
2016/02/01 Javascript
Node.js读取文件内容示例
2017/03/07 Javascript
ajax +NodeJS 实现图片上传实例
2017/06/06 NodeJs
Node 自动化部署的方法
2017/10/17 Javascript
Node.js利用console输出日志文件的方法示例
2018/04/27 Javascript
JavaScript反射与依赖注入实例详解
2018/05/29 Javascript
node中IO以及定时器优先级详解
2019/05/10 Javascript
React如何实现浏览器打印部分内容详析
2019/05/19 Javascript
js实现简单贪吃蛇游戏
2020/05/15 Javascript
vuex分模块后,实现获取state的值
2020/07/26 Javascript
JavaScript实现刮刮乐效果
2020/11/01 Javascript
[03:49]DOTA2 2015国际邀请赛中国区预选赛第二日现场百态
2015/05/27 DOTA
python 判断自定义对象类型
2009/03/21 Python
Python随机读取文件实现实例
2017/05/25 Python
在python win系统下 打开TXT文件的实例
2018/04/29 Python
Python实现查找二叉搜索树第k大的节点功能示例
2019/01/24 Python
详解Python对JSON中的特殊类型进行Encoder
2019/07/15 Python
Python如何把Spark数据写入ElasticSearch
2020/04/18 Python
windows下python 3.9 Numpy scipy和matlabplot的安装教程详解
2020/11/28 Python
Python+kivy BoxLayout布局示例代码详解
2020/12/28 Python
Beach Bunny Swimwear官网:设计师泳装和性感比基尼
2019/03/13 全球购物
银行先进个人事迹材料
2014/05/11 职场文书
大学生考试作弊检讨书
2014/09/21 职场文书
HTML速写之Emmet语法规则的实现
2021/04/07 HTML / CSS
springcloud之Feign超时问题的解决
2021/06/24 Java/Android
Java集成swagger文档组件
2021/06/28 Java/Android