使用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中针对函数处理的特殊方法
Mar 06 Python
Python抓取百度查询结果的方法
Jul 08 Python
python操作excel的方法(xlsxwriter包的使用)
Jun 11 Python
Python多进程池 multiprocessing Pool用法示例
Sep 07 Python
python pandas读取csv后,获取列标签的方法
Nov 12 Python
关于Django ForeignKey 反向查询中filter和_set的效率对比详解
Dec 15 Python
Python 数据库操作 SQLAlchemy的示例代码
Feb 18 Python
Python生成一个迭代器的实操方法
Jun 18 Python
python实现滑雪游戏
Feb 22 Python
python进度条显示-tqmd模块的实现示例
Aug 23 Python
Python实现机器学习算法的分类
Jun 03 Python
浅析Python中的随机采样和概率分布
Dec 06 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
一些花式咖啡的配方
2021/03/03 冲泡冲煮
PHP动态页生成静态页的3种常用方法
2014/11/13 PHP
Yii框架上传图片用法总结
2016/03/28 PHP
PHP实现权限管理功能示例
2017/09/22 PHP
javascript 动态参数判空操作
2008/12/22 Javascript
Mootools 1.2教程 滚动条(Slider)
2009/09/15 Javascript
读jQuery之三(构建选择器)
2011/06/11 Javascript
50个比较实用jQuery代码段
2011/09/18 Javascript
兼容ie、firefox的图片自动缩放的css跟js代码分享
2012/01/21 Javascript
三种检测iPhone/iPad设备方向的方法
2014/04/23 Javascript
js实现网页标题栏闪烁提示效果实例分析
2014/11/20 Javascript
jQuery插件简单实现方法
2015/07/18 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
EasyUI布局 高度自适应
2016/06/04 Javascript
利用Javascript实现BMI计算器
2016/08/16 Javascript
浅析JavaScript动画模拟拖拽原理
2016/12/09 Javascript
Angular2使用Angular CLI快速搭建工程(一)
2017/05/21 Javascript
快速解决vue动态绑定多个class的官方实例语法无效的问题
2018/09/05 Javascript
JavaScript实现连连看连线算法
2019/01/05 Javascript
vue 实现路由跳转时更改页面title
2019/11/05 Javascript
[01:17]Ti4 循环赛第一日回顾
2014/07/11 DOTA
使用Python编写Prometheus监控的方法
2018/10/15 Python
对python文件读写的缓冲行为详解
2019/02/13 Python
python删除文件夹下相同文件和无法打开的图片
2019/07/16 Python
在pytorch中实现只让指定变量向后传播梯度
2020/02/29 Python
详解webapp页面滚动卡顿的解决办法
2018/12/26 HTML / CSS
团队精神演讲稿
2013/12/31 职场文书
尽职尽责村干部自我鉴定
2014/01/23 职场文书
奥巴马连任演讲稿
2014/05/15 职场文书
安全责任书模板
2014/07/22 职场文书
小学生推普周国旗下讲话稿
2014/09/21 职场文书
小学二年级数学教学计划
2015/01/20 职场文书
大学生思想道德自我评价
2015/03/09 职场文书
2015年业务员工作总结范文
2015/04/07 职场文书
幼儿园庆六一主持词
2015/06/30 职场文书
Python基于百度API识别并提取图片中文字
2021/06/27 Python