使用Python的Treq on Twisted來進(jìn)行HTTP壓力測試
從事API相關(guān)的工作很有挑戰(zhàn)性,在高峰期保持系統(tǒng)的穩(wěn)定及健壯性就是其中之一,這也是我們在Mailgun做很多壓力測試的原因。
這么久以來,我們已經(jīng)嘗試了很多種方法,從簡單的ApacheBench到復(fù)雜些的自定義測試套。但是本貼講述的,是一種使用python進(jìn)行“快速粗糙”卻非常靈活的壓力測試的方法。
使用python寫HTTP客戶端的時候,我們都很喜歡用 Requests library。這也是我們向我們的API用戶們推薦的。Requests 很強大,但有一個缺點,它是一個模塊化的每線程一個調(diào)用的東西,很難或者說不可能用它來快速的產(chǎn)生成千上萬級別的請求。
Treq on Twisted簡介
為解決這個問題我們引入了Treq (Github庫)。Treq是一個HTTP客戶端庫,受Requests影響,但是它運行在Twisted上,具有Twisted典型的強大能力:處理網(wǎng)絡(luò)I/O時它是異步且高度并發(fā)的方式。
Treq并不僅僅限于壓力測試:它是寫高并發(fā)HTTP客戶端的好工具,比如網(wǎng)頁抓取。Treq很優(yōu)雅、易于使用且強大。這是一個例子:
>>> 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進(jìn)行轟炸。
#!/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()
輸出結(jié)果:
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”類的數(shù)字代表被Twisted反應(yīng)器準(zhǔn)備好但是還沒有發(fā)送的請求。這個腳本為了簡潔性忽略了所有錯誤處理。為它添加超時狀態(tài)的信息就留給讀者作為一個練習(xí)。
這個腳本可以當(dāng)做是一個起始點,你可以通過拓展改進(jìn)它來自定義特定應(yīng)用下的處理邏輯。建議你在改進(jìn)的時候用collections.Counter 來替代丑陋的全局變量。這個腳本運行在單線程上,想通過一臺機器壓榨出最大量的請求的話,你可以用類似 mulitprocessing 的技術(shù)手段。
愿你樂在壓力測試!
相關(guān)文章
Python測試框架:pytest學(xué)習(xí)筆記
這篇文章主要介紹了Python測試框架:pytest的相關(guān)資料,幫助大家更好的利用python進(jìn)行單元測試,感興趣的朋友可以了解下2020-10-10
Python數(shù)據(jù)可視化之用Matplotlib繪制常用圖形
Matplotlib能夠繪制折線圖、散點圖、柱狀圖、直方圖、餅圖. 我們需要知道不同的統(tǒng)計圖的意義,以此來決定選擇哪種統(tǒng)計圖來呈現(xiàn)我們的數(shù)據(jù),今天就帶大家詳細(xì)了解如何繪制這些常用圖形,需要的朋友可以參考下2021-06-06
Django Form設(shè)置文本框為readonly操作
這篇文章主要介紹了Django Form設(shè)置文本框為readonly操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
Python實現(xiàn)嵌套列表及字典并按某一元素去重復(fù)功能示例
這篇文章主要介紹了Python實現(xiàn)嵌套列表及字典并按某一元素去重復(fù)功能,涉及Python列表嵌套列表、列表嵌套字典,及按照某一元素去重復(fù)的相關(guān)操作方法,需要的朋友可以參考下2017-11-11
Python實現(xiàn)的旋轉(zhuǎn)數(shù)組功能算法示例
這篇文章主要介紹了Python實現(xiàn)的旋轉(zhuǎn)數(shù)組功能算法,結(jié)合實例形式總結(jié)分析了數(shù)組旋轉(zhuǎn)算法的原理與實現(xiàn)技巧,需要的朋友可以參考下2019-02-02

