聲明
本文由Donny譯自 3scale.com 的 《How to load test & tune performance on your API》
前言
這幾年API的作用不斷演化,以前API還只是用來做內(nèi)部系統(tǒng)之間的集成點仇让,但現(xiàn)在API已成為一個公司的核心系統(tǒng)登夫,一個構(gòu)建于Web和移動端應(yīng)用之上的核心系統(tǒng)哥攘。
當API僅只用來處理后臺的任務(wù)(例如生成報告),那么性能差點也不是問題率拒。但是如今API慢慢地發(fā)展成為連接服務(wù)與終端用戶的核心紐帶。這種關(guān)鍵性的角色變化表明了一個重要的觀點:那就是API的性能真的很重要。
如果API數(shù)據(jù)源響應(yīng)快玉工,前端的應(yīng)用程序的設(shè)計好點或差點影響不大,要是響應(yīng)慢如蝸牛淘菩,前端的設(shè)計再出色也是然并卵∽癜啵現(xiàn)在我們的客戶端應(yīng)用展示的數(shù)據(jù)源可能都是來自多個API響應(yīng)內(nèi)容的聚合,性能對這種微服務(wù)構(gòu)架來說真的非常重要潮改。
可以毫不夸張的說出色的性能就是你API提供的最好功能狭郑。我們知道向目標改進的唯一正確的方法就是找到問題的關(guān)鍵點,或者叫關(guān)鍵路徑汇在,并不斷迭代測量和調(diào)整你的架構(gòu)系統(tǒng)翰萨,直到系統(tǒng)達到預(yù)定的目標。對于API來說趾疚,測量和提高性能的過程就是負載與壓力測試的過程缨历。
本文將重點介紹如何對你的API進行負載壓力測試。我們會以一個簡單的糙麦、未測過的例子開始辛孵,然后再添加一個訪問控制層,要確保一切都經(jīng)過嚴格測試赡磅,做好處理真實流量的準備工作魄缚。OK,開始吧!
準備工作
首先我們要明確要測試什么冶匹,可以是對你所有的API接口嚼隘,或者是對單個API接口飞蛹,或是對需要排除故障或改進的API接口的常規(guī)測試。
本文的其部分,我們將使用一個示例API捕仔。這是一個棋牌類游戲的Node.js API暖呕。它有三個API接口:
/question – 返回一個隨機黑牌
/answer – 返回一個隨機白牌
/pick – 返回一對隨機的問題與答案
你測試用的負荷情況越和真實環(huán)境的越類似,你的負載測試就越有用霸旗。如果你不知道實際流量有多少或者你不知道負載在所有接口上是否都一致民晒,那么就算你知道你的API可以保持400 請求/秒的吞吐量也沒啥鳥用。
所以佛吓,你應(yīng)該先從收集你API的使用數(shù)據(jù)開始。你可以直接從你的API服務(wù)日志或者從其他你在用的應(yīng)用性能工具(例如New Relic)中獲取數(shù)據(jù)。在對你的API進行第一次測試之前耕陷,你應(yīng)該對以下問題做到心中有數(shù):
(1)每秒請求數(shù)的平均吞吐量(Average throughput in requests per second)
(2)峰值吞吐量(您在某段時間內(nèi)獲得的最大流量是多少?)(Peak throughput)
(3)API各接口的吞吐量分布情況(有沒有一些接口的流量遠超其他接口?)
(4)用戶的吞吐量分布情況(少數(shù)用戶產(chǎn)生大多數(shù)的流量崔慧,或者是更均勻分布皇钞?)
另外還需要考慮的一個關(guān)鍵點是隘世,在測試期間將要模擬的流量會是怎樣的,主要考慮點是:
(1)重復(fù)負載生成(Repetitive load generation)
(2)模擬流量模式
(3)真實流量
通常我們最好以最簡單的方法開始測試,然后逐步演化到更為接近真實環(huán)境的測試。我們可以先用重復(fù)負載生成來做為API接口的第一個測試,這樣不僅可以驗證我們的測試環(huán)境是否穩(wěn)定,更重要的是可以讓我們找到API能承受的最大吞吐量荣恐,這樣我們就可以知道API可以達到的性能上限是多少液斜。
找到你的API性能上限值后,你就可以開始考慮如何將你的生成的測試流量塑造得更接近真實環(huán)境。使用真實流量來測試是最理想的硼被,但實際操作不太可行。要模擬真實流量比較難嘉汰,也太花時間焙矛。所以我們有一個折中點的方法:先研究你的流量分析數(shù)據(jù),并做一個簡單的概率模擬残腌。比如你有100個API接口(提示:原文endpoint在這里我譯為接口蟆盹,翻譯成端點也可以孩灯,不過譯成接口感覺更容易理解),你檢查了上個月的使用情況逾滥,發(fā)現(xiàn)80%的流量來自20個接口峰档,其中3個接口占用了50%的流量。那么你就可以創(chuàng)建一個遵循這種概率的請求列表寨昙,并提供給你的負載測試工具讥巡。這樣做就相對快多了,并且它相對比較接近你真實負載舔哪,可以顯示出你實際環(huán)境中可能遇到的問題欢顷。
最后,如果你拿到你要測試的API的真實訪問日志捉蚤,你就可以用它們來做最接近客觀現(xiàn)實的測試吱涉。我們待會兒要討論的大部分負載測試工具,都是接收一個請求列表作為輸入文件外里。你可以用你的訪問日志,稍微做一個格式調(diào)整就可以匹配每個測試工具所需的格式特石。搞定這個你就可以在測試環(huán)境中輕松重現(xiàn)你的生產(chǎn)流量盅蝗。
配置你的負載測試環(huán)境
好了,你清楚了你要測試什么鬼了姆蘸,準備工作的最后一步就是配置好你的測試環(huán)境墩莫。你需要一個專用的測試環(huán)境。如果你不怕被你老板罵的話逞敷,或者比較任性狂秦,你也可以直接在你的生產(chǎn)環(huán)境中進行性能測試,不過出問題別說哥事先沒跟你說清楚哈推捐。
如果您已經(jīng)設(shè)好一個預(yù)生產(chǎn)或沙箱環(huán)境裂问,并且你的API也在上面運行了,那么你就萬事俱備了牛柒。因為本文要用示例API堪簿,我們會在AWS的服務(wù)實例上設(shè)置我們的環(huán)境。
在我們的例子中皮壁,我們使用一個簡單的API椭更,不需要從磁盤讀取或在內(nèi)存中保存大型數(shù)據(jù)集。我們選擇Linux C4.large實例就夠了蛾魄。
注意:我們對比過其他相似處理資源數(shù)但內(nèi)存更大的AWS實例虑瀑,但實際測試中內(nèi)存大部分沒使用湿滓,所以我們選了C4.large
接下來,我們將一個配好的負載測試實例(服務(wù)器)運行起來舌狗,這只是一個運行模擬測試程序的服務(wù)器叽奥,它會通過從多個并發(fā)連接重復(fù)發(fā)送請求到我們的API服務(wù)器。你需要模擬的負載越高把夸,機器的性能就要求越高而线。再次,這也是一個CPU密集型工作負載恋日。這里我們選擇具有4個虛擬核膀篮,16個 ECU的優(yōu)化處理器的c4.xlarge AWS服務(wù)器
我們選擇在相同的可用區(qū)內(nèi)部署所有實例(API服務(wù)器與測試服務(wù)器在同一個區(qū)/機房),這樣可以將外部因素對我們測試結(jié)果的影響降到最小岂膳。
選擇測試工具
我們有一個沙箱環(huán)境來運行我們的API誓竿,同時也有另一臺服務(wù)器準備開始負載測試。如果這是你第一次做性能測試谈截,你一定會想知道什么是最好的方法筷屡。在本節(jié)中,我們將會分享我們?nèi)绾芜x擇工具簸喂,同時也會介紹一下目前市面上一些公認比較好的工具毙死。
JMeter
在人們意識當中,首當翹楚的估計是Apache JMeter喻鳄,這是一個開源的Java程序扼倘,他關(guān)鍵的特性就是提供一個強大而完善的創(chuàng)建測試計劃的GUI。測試計劃由測試組件組成除呵,測試組件定義了測試的每一個部分再菊,例如:
(1)用來注入負載測試的線程
(2)參數(shù)化測試中使用的HTTP請求
(3)可添加偵聽器,象widget測試組件那樣颜曾,可以以不同的方式顯示測主式結(jié)果
優(yōu)點:
(1)它是功能性負載測試的最好工具纠拔。你可以設(shè)定條件來為復(fù)雜的用戶流建模,還可以創(chuàng)建斷言來驗證行為泛豪。
(2)輕松模擬復(fù)雜的http請求稠诲,比如請求前的登錄驗證或文件上傳
(3)可擴展性強,有很多社區(qū)插件可以修改或擴展內(nèi)置的行為
(4)開源并且免費
缺點:
(1)GUI學(xué)習(xí)曲線陡峭诡曙,一大堆的選項吕粹,在你運行第一個測試之前你得了解大量的概念。
(2)測試高負載時岗仑,操作步驟很麻煩匹耕。你需要先使用GUI工具來生成XML測試計劃,然后在非GUI模式下導(dǎo)入測試計劃運行測試荠雕,因為GUI會消耗掉本用于生成負載的大量資源稳其。你還需要注意所有的偵聽器(收集數(shù)據(jù)與展示測量的組件)哪些要被禁用或啟用驶赏,因為它們也很耗資源。測試結(jié)束后后既鞠,你需要將原始結(jié)果數(shù)據(jù)導(dǎo)入GUI以才能查看結(jié)果煤傍。
(3)如果你的目標是測試一段時間內(nèi)的持續(xù)吞吐量(例如在60秒內(nèi)每秒請求1000次),那么很難找到正確的并發(fā)線程數(shù)量和計時器來求出一個比較穩(wěn)定的數(shù)值嘱蛋。
JMeter只是我們在開始測試時用的工具蚯姆,我們很快開始尋找其他替代方案。原因是洒敏,如果你的目標是在Web應(yīng)用上壓力測試復(fù)雜的用戶流龄恋,那么JMeter可能是最好的工具,但如果你只是需要在一些HTTP API接口上進行性能測試凶伙,那用它就是殺雞用牛刀了郭毕。
Wrk
Wrk是一款和傳統(tǒng)的Apache Benchmark(最初用來做Apache服務(wù)器的測試工具)非常相似的工具。wrk和ab完全不同于JMeter:
(1)一切都是可以通過命令行工具配置和執(zhí)行的函荣。
(2)配置少但強大显押,只有基本生成HTTP負載的必要幾項配置
(3)性能強悍
然而,和傳統(tǒng)ab工具相比還是有幾個優(yōu)勢的地方傻挂,主要是:
(1)多線程乘碑,所以能利用多核處理器的優(yōu)勢,更容易生成更高的負載
(2)利用Lua腳本很容易進行擴展默認的行為
不好的地方金拒,主要是生成的默認報告在內(nèi)容與格式上都受到限制(僅文本兽肤,無繪圖)。當你的目標是找到你的API可以處理的最大負載量殖蚕,那么wrk是你最佳選擇工具。wrk用起來很快就可以上手沉迹。
Vegeta
Vegeta是一款開源命令行工具睦疫,但它采用的方式不同于我們以前所見的工具。它專注于如何達到與維持每秒請求數(shù)速率鞭呕。也就是說它側(cè)重在測試支撐每秒X次請求時API會有怎樣的服務(wù)行為蛤育,當你有實際的數(shù)據(jù)或?qū)δ銓⒁_到的峰值流量有個估算時就非常有用,你可以用于驗證你的API是否能滿足你的需求葫松。
SaaS 工具
正如你之前所看到的瓦糕,運行一個簡單的負載測試需要準備好配置環(huán)境。最近有些產(chǎn)品提供負載測試服務(wù)腋么。我們試過兩個咕娄,Loader.io和Blazemeter(話外:阿里也有性能測試工具PTS,老外估計沒試過)珊擂。
注意:我們只試了這兩個工具的免費版圣勒,所以得到的測試結(jié)果僅適用于免費版的限定费变。
Blazemeter
這個產(chǎn)品和我們前面提到的JMeter一樣有同樣的毛病:如果你只需要用在高負載測試圣贸,你需要在GUI界面上創(chuàng)建測試計劃挚歧,然后在另一個運行非GUI模式的JMeter中導(dǎo)入這些計劃。Blazemeter允許你上傳JMeter的測試計劃到他們的云端并運行吁峻,但可惜的是免費版只能設(shè)置50個并發(fā)用戶滑负。
Loader.io
它是一款SendGrid出品的簡單而強大的云負載測試服務(wù)工具。它有你所需要的功能和漂亮的可視報告用含。 Loader.io 的免費版還是不錯的矮慕,每秒最多可以有10000次請求的吞吐量,你基本上就可以用它來運行一個真實的負載測試耕餐。
我們推薦使用多個工具凡傅,以便可以多重檢查我們的測試結(jié)果,不同的工具有不同的功能與方法肠缔,可以更多方面地反映測試結(jié)果夏跷。
建立測試基線
我們先嘗試找到我們的API可以承受的最大吞吐量。在這個吞吐量下明未,我們的API服務(wù)達到最大CPU利用率槽华,同時不會返回任何錯誤或超時。這個吞吐量就可作為我們后面測試要用的每秒請求數(shù)趟妥。
同樣猫态,重要的是要注意到:CPU是限制因素之一,但你也還必須清楚地知道哪些資源會成為你API的性能瓶頸披摄。
我們有必要在API服務(wù)器上安裝一些工具亲雪,以便我們在測試過程中監(jiān)控資源的利用率情況。我們使用?Keymetrics.io?和?PM2?模塊疚膊。
我們的Node.js應(yīng)用運行了一個非常簡單的HTTP 服務(wù)义辕。Node.js是單線程設(shè)計的,但為了利用c4.large AWS實例中提供的雙核寓盗,我們使用PM2的集群功能來運行應(yīng)用程序的兩個工作進程灌砖。
由于我們的API是完全無狀態(tài)的,所以很容易使用PM2的 核心集群模塊(PM2在內(nèi)部直接使用)傀蚌。PM2提供的集群功能提供了不錯的快捷命令來start/stop/reload應(yīng)用程序基显,也可以監(jiān)控進程。
首次運行
我們先使用Loader.io對API進行測試善炫。以下是持續(xù)30秒撩幽,每秒10,000次請求的測試結(jié)果,10000次請求是Loader.io免費版中允許的最大吞吐量箩艺。
在測試期間摸航,我們觀察到API服務(wù)器的CPU處理器在測試期間只有幾次達到100%的容量制跟。
這表示我們的API可能還可以處理更高的吞吐量。我們接下來通過運行wrk進行第二次測試證實了這一點酱虎。我們的目標就是要將我們的API服務(wù)器性能推到極限雨膨。
wrk -t 4 -c 1000 -d 60 --latency --timeout 3s http://api-server/questions
這里是我們對這個測試做了多次重復(fù)測試的結(jié)果:
Running 1m test @ http://api-server/question
4 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 62.23ms 30.85ms 1.35s 99.39%
Req/Sec 4.07k 357.61 5.27k 94.29%
Latency Distribution
50% 60.04ms
75% 63.85ms
90% 64.17ms
99% 75.86ms
972482 requests in 1.00m, 189.89MB read
Requests/sec: 16206.04
Transfer/sec: 3.16MB
結(jié)果表明,我們的預(yù)感被證實:它達到16,206請求/秒读串,同時保持合理的延遲聊记,第99百分位只有75.86毫秒。 我們將這作為我們的基準最大吞吐量恢暖,因為這一次我們看到了API服務(wù)器的最大容量處理能力:
接下來
我們剛看到用一個簡單的方式來找出你的API可承受的最大流量負載排监,同時在這過程中我們介紹并討論了我們看到的一些工具。
請繼續(xù)關(guān)注本文的第二部分杰捂,我們將介紹如何控制流量舆床,不要讓隨隨便便一個客戶端就可以輕松搞跨您的API。 我們將展示如何通過在架構(gòu)前端添加代理來確保我們的API的性能不受影響嫁佳。