使用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使用7z解压软件备份文件脚本分享
Feb 21 Python
python flask解析json数据不完整的解决方法
May 26 Python
Django Rest framework权限的详细用法
Jul 25 Python
Python 一键获取百度网盘提取码的方法
Aug 01 Python
python字符串格式化方式解析
Oct 19 Python
Python协程 yield与协程greenlet简单用法示例
Nov 22 Python
python如何使用jt400.jar包代码实例
Dec 20 Python
python mysql自增字段AUTO_INCREMENT值的修改方式
May 18 Python
keras之权重初始化方式
May 21 Python
matplotlib 生成的图像中无法显示中文字符的解决方法
Jun 10 Python
详解python tkinter 图片插入问题
Sep 03 Python
pandas实现导出数据的四种方式
Dec 13 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中理解print EOT分界符和echo EOT的用法区别小结
2010/02/21 PHP
兼容各大浏览器带关闭按钮的漂浮多组图片广告代码
2014/06/05 PHP
php模板引擎技术简单实现
2016/03/15 PHP
yii框架使用分页的方法分析
2019/07/25 PHP
利用javascript移动div层-javascript 拖动层
2009/03/22 Javascript
基于jquery1.4.2的仿flash超炫焦点图播放效果
2010/04/20 Javascript
jquery下为Event handler传递动态参数的代码
2011/01/06 Javascript
jQuery的context属性用法实例
2014/12/27 Javascript
jQuery源码分析之jQuery.fn.each与jQuery.each用法
2015/01/23 Javascript
js控制页面的全屏展示和退出全屏显示的方法
2015/03/10 Javascript
JS实现鼠标滑过折叠与展开菜单效果代码
2015/09/06 Javascript
使用jQuery判断浏览器滚动条位置的方法
2016/05/30 Javascript
jquery中用jsonp实现搜索框功能
2016/10/18 Javascript
微信小程序画布圆形进度条显示效果
2020/11/17 Javascript
vue-cli的build的文件夹下没有dev-server.js文件配置mock数据的方法
2019/04/17 Javascript
详解ES6 CLASS在微信小程序中的应用实例
2020/04/24 Javascript
全面解析js中的原型,原型对象,原型链
2021/01/25 Javascript
[02:28]DOTA2英雄基础教程 灰烬之灵
2013/12/19 DOTA
[05:14]辉夜杯主赛事第二日 RECAP精彩回顾
2015/12/27 DOTA
python抓取网页中链接的静态图片
2018/01/29 Python
攻击者是如何将PHP Phar包伪装成图像以绕过文件类型检测的(推荐)
2018/10/11 Python
python利用opencv实现SIFT特征提取与匹配
2020/03/05 Python
ipython jupyter notebook中显示图像和数学公式实例
2020/04/15 Python
解决pytorch 交叉熵损失输出为负数的问题
2020/07/07 Python
Python实现自动签到脚本的示例代码
2020/08/19 Python
python闭包与引用以及需要注意的陷阱
2020/09/18 Python
写好求职应聘自荐信的三部曲
2013/09/21 职场文书
加拿大留学自荐信
2014/01/28 职场文书
残疾人小组计划书
2014/04/27 职场文书
励志演讲稿600字
2014/08/21 职场文书
公司的门卫岗位职责
2014/09/09 职场文书
2014乡镇班子个人对照检查材料思想汇报
2014/09/26 职场文书
优秀班集体申报材料
2014/12/25 职场文书
会计专业自荐信范文
2019/05/22 职场文书
vue3中provide && inject的使用
2021/07/01 Vue.js
一小时迅速入门Mybatis之bind与多数据源支持 Java API
2021/09/15 Javascript