使用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和perl实现批量对目录下电子书文件重命名的代码分享
Nov 21 Python
Python中使用不同编码读写txt文件详解
May 28 Python
Python实现在线暴力破解邮箱账号密码功能示例【测试可用】
Sep 06 Python
Python装饰器用法实例总结
Feb 07 Python
在python带权重的列表中随机取值的方法
Jan 23 Python
Win系统PyQt5安装和使用教程
Dec 25 Python
pytorch 模拟关系拟合——回归实例
Jan 14 Python
Django中ORM找出内容不为空的数据实例
May 20 Python
python根据字典的键来删除元素的方法
Aug 16 Python
Python爬取微信小程序通用方法代码实例详解
Sep 29 Python
Django配置跨域并开发测试接口
Nov 04 Python
python爬取企查查企业信息之selenium自动模拟登录企查查
Apr 08 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简单实现DES加密解密的方法
2016/07/12 PHP
PHP实现导出带样式的Excel
2016/08/28 PHP
php 二维数组时间排序实现代码
2016/11/19 PHP
Laravel如何友好的修改.env配置文件详解
2017/06/07 PHP
laravel-admin 后台表格筛选设置默认的查询日期方法
2019/10/03 PHP
jQuery消息提示框插件Tipso
2015/05/04 Javascript
jQuery Easy UI中根据第一个下拉框选中的值设置第二个下拉框是否可以编辑
2016/11/29 Javascript
15个非常实用的JavaScript代码片段
2016/12/18 Javascript
js实现文字选中分享功能
2017/01/25 Javascript
微信小程序 侧滑删除(左滑删除)
2017/05/23 Javascript
认识jQuery的Promise的具体使用方法
2017/10/10 jQuery
ajaxfileupload.js实现上传文件功能
2019/04/19 Javascript
微信小程序收货地址API兼容低版本解决方法
2019/05/18 Javascript
javascript实现抢购倒计时程序
2019/08/26 Javascript
js+canvas实现两张图片合并成一张图片的方法
2019/11/01 Javascript
javascript设计模式 ? 策略模式原理与用法实例分析
2020/04/21 Javascript
解决VUE项目localhost端口服务器拒绝连接,只能用127.0.0.1的问题
2020/08/14 Javascript
微信小程序实现签到弹窗动画
2020/09/21 Javascript
微信小程序学习之自定义滚动弹窗
2020/12/20 Javascript
python的类方法和静态方法
2014/12/13 Python
python类的继承实例详解
2017/03/30 Python
python实现UDP协议下的文件传输
2020/03/20 Python
宝塔面板成功部署Django项目流程(图文)
2020/06/22 Python
html5教程调用绘图api画简单的圆形代码分享
2013/12/04 HTML / CSS
Under Armour安德玛中国官网:美国高端运动科技品牌
2018/03/09 全球购物
Halston Heritage官网:简洁的日装,稍显奢华的晚装
2018/11/20 全球购物
精灵市场:Pixie Market
2019/06/18 全球购物
小蚁科技官方商店:YI Technology
2019/08/23 全球购物
JAVA程序员面试题
2012/10/03 面试题
重阳节登山活动方案
2014/02/03 职场文书
作文批改评语大全
2014/04/23 职场文书
《百分数的认识》教学反思
2016/02/19 职场文书
python单元测试之pytest的使用
2021/06/07 Python
JPA 通过Specification如何实现复杂查询
2021/11/23 Java/Android
APP界面设计技巧和注意事项
2022/04/29 杂记
SQL Server数据库备份和恢复数据库的全过程
2022/06/14 SQL Server