使用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 运算符 供重载参考
Jun 11 Python
python3实现TCP协议的简单服务器和客户端案例(分享)
Jun 14 Python
Django自定义过滤器定义与用法示例
Mar 22 Python
python实现在IDLE中输入多行的方法
Apr 19 Python
PyQt5每天必学之关闭窗口
Apr 19 Python
浅谈dataframe中更改列属性的方法
Jul 10 Python
python正则表达式去除两个特殊字符间的内容方法
Dec 24 Python
python2使用bs4爬取腾讯社招过程解析
Aug 14 Python
python读取指定字节长度的文本方法
Aug 27 Python
Python实现初始化不同的变量类型为空值
Jun 02 Python
pyqt5 textEdit、lineEdit操作的示例代码
Aug 12 Python
Golang Web 框架Iris安装部署
Aug 14 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 启动报错如何解决
2014/01/17 PHP
php邮箱地址正则表达式验证
2015/11/13 PHP
yii2项目实战之restful api授权验证详解
2017/05/20 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
2020/02/27 PHP
jquery 简单导航实现代码
2009/09/11 Javascript
jQuery1.3.2 升级到jQuery1.4.4需要修改的地方
2011/01/06 Javascript
node.js中的fs.lstatSync方法使用说明
2014/12/16 Javascript
jQuery实现手机号码输入提示功能实例
2015/04/30 Javascript
基于JS实现PHP的sprintf函数实例
2015/11/14 Javascript
跟我学习javascript的var预解析与函数声明提升
2015/11/16 Javascript
ES6中非常实用的新特性介绍
2016/03/10 Javascript
AngularJS基础 ng-mouseleave 指令详解
2016/08/02 Javascript
浅谈js函数中的实例对象、类对象、局部变量(局部函数)
2016/11/20 Javascript
js实现时间轴自动排列效果
2017/03/09 Javascript
Mac系统下Webstorm快捷键整理大全
2017/05/28 Javascript
vue、react等单页面项目部署到服务器的方法及vue和react的区别
2018/09/29 Javascript
JS获取当前时间的实例代码(昨天、今天、明天)
2018/11/13 Javascript
[26:52]LGD vs EG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
[42:50]NB vs VP 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python文件与文件夹常见基本操作总结
2016/09/19 Python
Python中Threading用法详解
2017/12/27 Python
python实现屏保计时器的示例代码
2018/08/08 Python
python内置数据类型之列表操作
2018/11/12 Python
在vscode中配置python环境过程解析
2019/09/28 Python
python安装sklearn模块的方法详解
2020/11/28 Python
免费获得微软MCSD证书赶快行动吧!
2012/11/13 HTML / CSS
不可轻视HTML5!App三年内将被html5顶替彻底消失
2015/11/18 HTML / CSS
求职信范文英文版
2014/01/05 职场文书
违反工作纪律检讨书
2014/02/15 职场文书
诉前财产保全担保书
2014/05/20 职场文书
施工安全汇报材料
2014/08/17 职场文书
无私奉献演讲稿
2014/09/04 职场文书
律师催款函范文
2015/06/24 职场文书
关于python pygame游戏进行声音添加的技巧
2021/10/24 Python
如何通过一篇文章了解Python中的生成器
2022/04/02 Python
Android Studio实现带三角函数对数运算功能的高级计算器
2022/05/20 Java/Android