使用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如何生成随机密码
Apr 20 Python
python编程实现希尔排序
Apr 13 Python
python中Pycharm 输出中文或打印中文乱码现象的解决办法
Jun 16 Python
Python中序列的修改、散列与切片详解
Aug 27 Python
python email smtplib模块发送邮件代码实例
Apr 26 Python
Python 输入一个数字判断成绩分数等级的方法
Nov 15 Python
如何用Python做一个微信机器人自动拉群
Jul 03 Python
如何实现Django Rest framework版本控制
Jul 25 Python
如何在python中实现随机选择
Nov 02 Python
python、Matlab求定积分的实现
Nov 20 Python
django在开发中取消外键约束的实现
May 20 Python
python 爬取吉首大学网站成绩单
Jun 02 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学习之运算符相关概念
2011/06/09 PHP
PHP图片处理之图片旋转和图片翻转实例
2014/11/19 PHP
PHP url的pathinfo模式加载不同控制器的简单实现
2016/08/12 PHP
为何说PHP引用是个坑,要慎用
2018/04/02 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
2020/02/28 PHP
jquery last-child 列表最后一项的样式
2010/01/22 Javascript
jquery遍历select元素(实例讲解)
2013/12/31 Javascript
JS替换字符串中字符即替换全部而不是第一个
2014/06/04 Javascript
浅谈js中的三种继承方式及其优缺点
2016/08/10 Javascript
jQuery EasyUI 页面加载等待及页面等待层
2017/02/06 Javascript
js实现PC端和移动端刮卡效果
2020/03/27 Javascript
layer弹出层中H5播放器全屏出错的解决方法
2017/02/21 Javascript
jQuery鼠标悬停内容动画切换效果
2017/04/27 jQuery
nodejs使用http模块发送get与post请求的方法示例
2018/01/08 NodeJs
Django+Vue实现WebSocket连接的示例代码
2019/05/28 Javascript
vue动态路由:路由参数改变,视图不更新问题的解决
2019/11/05 Javascript
js实现鼠标切换图片(无定时器)
2021/01/27 Javascript
[01:11:27]2018DOTA2亚洲邀请赛小组赛 A组加赛 Newbee vs Optic
2018/04/03 DOTA
pygame播放音乐的方法
2015/05/19 Python
python学习入门细节知识点
2018/03/29 Python
使用python实现快速搭建简易的FTP服务器
2018/09/12 Python
Python tkinter label 更新方法
2018/10/11 Python
Django如何简单快速实现PUT、DELETE方法
2019/07/24 Python
简单了解python中的f.b.u.r函数
2019/11/02 Python
Python While循环语句实例演示及原理解析
2020/01/03 Python
django之从html页面表单获取输入的数据实例
2020/03/16 Python
Django-xadmin+rule对象级权限的实现方式
2020/03/30 Python
检测用户浏览器是否支持CSS3的方法
2009/08/29 HTML / CSS
Superdry瑞典官网:英国日本街头风品牌
2017/05/17 全球购物
main 主函数执行完毕后,是否可能会再执行一段代码,给出说明
2012/12/05 面试题
计算机应用毕业生自荐信
2013/10/23 职场文书
验房委托书
2014/08/30 职场文书
出纳岗位职责
2015/01/31 职场文书
大学生预备党员自我评价
2015/03/04 职场文书
停水通知
2015/04/16 职场文书
Python中的np.argmin()和np.argmax()函数用法
2021/06/02 Python