使用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实现统计单词出现的个数
May 28 Python
Python中的groupby分组功能的实例代码
Jul 11 Python
python中类的属性和方法介绍
Nov 27 Python
python3实现多线程聊天室
Dec 12 Python
Python 日志logging模块用法简单示例
Oct 18 Python
Python OrderedDict的使用案例解析
Oct 25 Python
基于Python编写一个计算器程序,实现简单的加减乘除和取余二元运算
Aug 05 Python
python 深度学习中的4种激活函数
Sep 18 Python
Python高并发和多线程有什么关系
Nov 14 Python
Python实现Word文档转换Markdown的示例
Dec 22 Python
详解在OpenCV中如何使用图像像素
Mar 03 Python
Python中使用tkFileDialog实现文件选择、保存和路径选择
May 20 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
欧美媒体选出10年前最流行的17部动画
2017/01/18 日漫
joomla内置的表单验证功能使用方法
2010/06/11 PHP
php数组函数序列之sort() 对数组的元素值进行升序排序
2011/11/02 PHP
phpize的深入理解
2013/06/03 PHP
PHP读取CSV大文件导入数据库的实例
2017/07/24 PHP
在Laravel5中正确设置文件权限的方法
2019/05/22 PHP
javascript OFFICE控件测试代码
2009/12/08 Javascript
Js制作简单弹出层DIV在页面居中 中间显示遮罩的具体方法
2013/08/08 Javascript
js判断运行jsp页面的浏览器类型以及版本示例
2013/10/30 Javascript
javascript 循环调用示例介绍
2013/11/20 Javascript
JavaScript调试技巧之console.log()详解
2014/03/19 Javascript
jQuery插件实现控制网页元素动态居中显示
2015/03/24 Javascript
JavaScript中用getDate()方法返回指定日期的教程
2015/06/09 Javascript
Jquery ajax加载等待执行结束再继续执行下面代码操作
2015/11/24 Javascript
很全面的JavaScript常用功能汇总集合
2016/01/22 Javascript
jQuery simpleModal插件的使用介绍
2016/08/30 Javascript
Angular.js中$apply()和$digest()的深入理解
2016/10/13 Javascript
JavaScript日期选择功能示例
2017/01/16 Javascript
JS对象深度克隆实例分析
2017/03/16 Javascript
jQuery轻松实现无缝轮播效果
2017/03/22 jQuery
简单谈谈关于 npm 5.0 的新坑
2017/06/08 Javascript
详解webpack介绍&amp;安装&amp;常用命令
2017/06/29 Javascript
JS实现去除数组中重复json的方法示例
2017/12/21 Javascript
JS实现获取word文档内容并输出显示到html页面示例
2018/06/23 Javascript
AngularJs的UI组件ui-Bootstrap之Tooltip和Popover
2018/07/13 Javascript
Vue $emit $refs子父组件间方法的调用实例
2018/09/12 Javascript
Vue 递归多级菜单的实例代码
2019/05/05 Javascript
使用JavaScript获取扫码枪扫描得到的条形码的思路代码详解
2020/06/10 Javascript
canvas实现图片马赛克的示例代码
2018/03/26 HTML / CSS
美国男装连锁零售商:Men’s Wearhouse
2016/10/14 全球购物
Android面试宝典
2013/08/06 面试题
高中校园广播稿
2014/01/11 职场文书
2014年最新学校运动会广播稿
2014/09/17 职场文书
护士自我推荐信范文
2015/03/24 职场文书
Python绘制地图神器folium的新人入门指南
2021/05/23 Python
十大最强水系宝可梦,最美宝可梦排第三,榜首大家最熟悉
2022/03/18 日漫