使用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利用elaphe制作二维条形码实现代码
May 25 Python
归纳整理Python中的控制流语句的知识点
Apr 14 Python
python任务调度实例分析
May 19 Python
python实现的系统实用log类实例
Jun 30 Python
Python实现线程状态监测简单示例
Mar 28 Python
在Pycharm中自动添加时间日期作者等信息的方法
Jan 16 Python
深入了解Django中间件及其方法
Jul 26 Python
Python3分析处理声音数据的例子
Aug 27 Python
信号生成及DFT的python实现方式
Feb 25 Python
Python多线程正确用法实例解析
May 30 Python
Keras中的两种模型:Sequential和Model用法
Jun 27 Python
Python list去重且保持原顺序不变的方法
Apr 03 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
COM in PHP (winows only)
2006/10/09 PHP
Parse正式发布开源PHP SDK
2014/08/11 PHP
使用PHP similar text计算两个字符串相似度
2015/11/06 PHP
javascript 面向对象编程基础 多态
2009/08/21 Javascript
javascript 简单抽屉效果的实现代码
2010/03/09 Javascript
js+div实现图片滚动效果代码
2014/02/10 Javascript
jquery无刷新验证邮箱地址实现实例
2014/02/19 Javascript
javascript实现简单的鼠标拖动效果实例
2015/04/10 Javascript
JavaScript实现的微信二维码图片生成器的示例
2016/10/26 Javascript
Vuex模块化实现待办事项的状态管理
2017/03/15 Javascript
Ajax异步文件上传与NodeJS express服务端处理
2017/04/01 NodeJs
vue的.vue文件是怎么run起来的(vue-loader)
2018/12/10 Javascript
详解微信小程序开发(项目从零开始)
2019/06/06 Javascript
为什么Vue3.0使用Proxy实现数据监听(defineProperty表示不背这个锅)
2019/10/14 Javascript
Element实现表格嵌套、多个表格共用一个表头的方法
2020/05/09 Javascript
[03:14]2014DOTA2西雅图国际邀请赛 EG战队巡礼
2014/07/07 DOTA
Python的Django框架中自定义模版标签的示例
2015/07/20 Python
CentOS中升级Python版本的方法详解
2017/07/10 Python
python字符串和常用数据结构知识总结
2019/05/21 Python
Python读写锁实现实现代码解析
2020/11/28 Python
python实现三种随机请求头方式
2021/01/05 Python
支持IE8的纯css3开发的响应式设计动画菜单教程
2014/11/05 HTML / CSS
Cotton On香港网站:澳洲时装连锁品牌
2018/11/01 全球购物
威盛公司软件C++工程师笔试题面试题
2012/07/16 面试题
环境工程专业个人求职信
2013/12/05 职场文书
入党自我评价范文
2014/02/02 职场文书
三分钟演讲稿事例
2014/03/03 职场文书
责任心演讲稿
2014/05/14 职场文书
药店采购员岗位职责
2014/09/30 职场文书
小学家长通知书评语
2014/12/31 职场文书
限期整改通知书
2015/04/22 职场文书
对学校的意见和建议
2015/06/04 职场文书
辅导员学期工作总结
2015/08/14 职场文书
早安问候语大全
2015/11/10 职场文书
PyCharm 配置SSH和SFTP连接远程服务器
2022/05/11 Python