使用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实现计算文件夹下.h和.cpp文件的总行数
Apr 23 Python
python学习笔记之调用eval函数出现invalid syntax错误问题
Oct 18 Python
Python常见格式化字符串方法小结【百分号与format方法】
Sep 18 Python
Python语言描述随机梯度下降法
Jan 04 Python
Python PIL读取的图像发生自动旋转的实现方法
Jul 05 Python
详解pandas数据合并与重塑(pd.concat篇)
Jul 09 Python
Django restframework 框架认证、权限、限流用法示例
Dec 21 Python
Tensorflow卷积实现原理+手写python代码实现卷积教程
May 22 Python
TensorFlow保存TensorBoard图像操作
Jun 23 Python
套娃式文件夹如何通过Python批量处理
Aug 23 Python
解决pycharm不能自动保存在远程linux中的问题
Feb 06 Python
用python自动生成日历
Apr 24 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高手?学会“懒惰”的编程
2006/12/05 PHP
用Zend Studio+PHPnow+Zend Debugger搭建PHP服务器调试环境步骤
2014/01/19 PHP
PHP生成各种常见验证码和Ajax验证过程
2016/01/10 PHP
js数组Array sort方法使用深入分析
2013/02/21 Javascript
原生js实现给指定元素的后面追加内容
2013/04/10 Javascript
用js代码改变单选框选中状态的简单实例
2013/12/18 Javascript
javascript实现类似超链接的效果
2014/12/26 Javascript
javascript常用函数(1)
2015/11/04 Javascript
JavaScript File分段上传
2016/03/10 Javascript
jQuery对checkbox 复选框的全选全不选反选的操作
2016/08/09 Javascript
详解Angular2中Input和Output用法及示例
2017/05/21 Javascript
详解利用 Express 托管静态文件的方法
2017/09/18 Javascript
vue动态配置模板 'component is'代码
2019/07/04 Javascript
解决layui-table单元格设置为百分比在ie8下不能自适应的问题
2019/09/28 Javascript
jQuery实现B2B网站后台管理系统侧导航
2020/07/08 jQuery
node koa2 ssr项目搭建的方法步骤
2020/12/11 Javascript
[48:35]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 TNC vs Optic
2018/04/03 DOTA
python网络编程之数据传输UDP实例分析
2015/05/20 Python
python进阶_浅谈面向对象进阶
2017/08/17 Python
Python图像处理之识别图像中的文字(实例讲解)
2018/05/10 Python
对python程序内存泄漏调试的记录
2018/06/11 Python
在Python中输入一个以空格为间隔的数组方法
2018/11/13 Python
Python中Unittest框架的具体使用
2019/08/27 Python
Python3.7 pyodbc完美配置访问access数据库
2019/10/03 Python
给keras层命名,并提取中间层输出值,保存到文档的实例
2020/05/23 Python
最新PyCharm从安装到PyCharm永久激活再到PyCharm官方中文汉化详细教程
2020/11/17 Python
Lampenwelt德国:欧洲领先的灯具和照明在线商店
2018/08/05 全球购物
遥感技术与仪器求职信
2014/02/22 职场文书
乡村文明行动实施方案
2014/03/29 职场文书
高中同学会活动方案
2014/08/14 职场文书
2015年班组工作总结
2015/04/20 职场文书
2015年幼儿园班主任工作总结
2015/05/12 职场文书
运动会闭幕式主持词
2015/07/01 职场文书
教导处教学工作总结
2015/08/12 职场文书
为什么说餐饮很难做,是因为你不了解这些新规则
2019/08/20 职场文书
导游词之云南丽江-泸沽湖
2019/09/26 职场文书