使用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解压apk包的方法
Apr 18 Python
Python中的lstrip()方法使用简介
May 19 Python
wxPython之解决闪烁的问题
Jan 15 Python
python 爬虫 批量获取代理ip的实例代码
May 22 Python
解决Python3.5+OpenCV3.2读取图像的问题
Dec 05 Python
Python 实现中值滤波、均值滤波的方法
Jan 09 Python
python 将有序数组转换为二叉树的方法
Mar 26 Python
利用Python代码实现一键抠背景功能
Dec 29 Python
利用python在excel中画图的实现方法
Mar 17 Python
pytorch 查看cuda 版本方式
Jun 23 Python
python xlsxwriter模块的使用
Dec 24 Python
python 提取html文本的方法
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
PHP中对数据库操作的封装
2006/10/09 PHP
php5.5中类级别的常量使用介绍
2013/10/02 PHP
php中使用gd库实现下载网页中所有图片
2015/05/12 PHP
解决PHP里大量数据循环时内存耗尽的方法
2015/10/10 PHP
php获取字符串前几位的实例(substr返回字符串的子串用法)
2017/03/08 PHP
浅谈使用 Yii2 AssetBundle 中 $publishOptions 的正确姿势
2017/11/08 PHP
Javascript 验证上传图片大小[客户端]
2009/08/01 Javascript
javascript 实现字符串反转的三种方法
2013/11/23 Javascript
js网页右下角提示框实例
2014/10/14 Javascript
基于javascript实现浏览器滚动条快到底部时自动加载数据
2015/11/30 Javascript
JavaScript 正则表达式中global模式的特性
2016/02/25 Javascript
JavaScript 经典实例日常收集整理(常用经典)
2016/03/30 Javascript
jquery实现界面无刷新加载登陆注册
2016/07/30 Javascript
浅谈JS中的三种字符串连接方式及其性能比较
2016/09/02 Javascript
javascript 定时器工作原理分析
2016/12/03 Javascript
微信小程序之拖拽排序(代码分享)
2017/01/21 Javascript
JS对象与JSON互转换、New Function()、 forEach()、DOM事件流等js开发基础小结
2017/08/10 Javascript
js实现数组内数据的上移和下移的实例
2017/11/14 Javascript
webpack+vue2构建vue项目骨架的方法
2018/01/09 Javascript
详解html-webpack-plugin用法全解
2018/01/22 Javascript
微信小程序使用canvas自适应屏幕画海报并保存图片功能
2019/07/25 Javascript
微信小程序实现下滑到底部自动翻页功能
2020/03/07 Javascript
Vue中nprogress页面加载进度条的方法实现
2020/11/13 Javascript
让python 3支持mysqldb的解决方法
2017/02/14 Python
Python实现的基于优先等级分配糖果问题算法示例
2018/04/25 Python
css3动画效果抖动解决方法
2018/09/03 HTML / CSS
使用placeholder属性设置input文本框的提示信息
2020/02/19 HTML / CSS
什么是java序列化,如何实现java序列化
2012/11/14 面试题
个人生活学习自我评价范文
2013/11/26 职场文书
剪彩仪式主持词
2014/03/19 职场文书
父母对孩子说的话
2014/04/12 职场文书
护理见习报告范文
2014/11/03 职场文书
质量保证书格式模板
2015/02/27 职场文书
退休教师追悼词
2015/06/23 职场文书
Python趣味挑战之实现简易版音乐播放器
2021/05/28 Python
MybatisPlus代码生成器的使用方法详解
2021/06/13 Java/Android