壓力測(cè)試
壓測(cè)結(jié)果受到哪些因素影響?
- 壓力機(jī)到服務(wù)器的網(wǎng)絡(luò)延遲 (建議內(nèi)網(wǎng)或本機(jī)壓測(cè))
- 壓力機(jī)到服務(wù)器的帶寬 (建議內(nèi)網(wǎng)或本機(jī)壓測(cè))
- 是否開(kāi)啟HTTP keep-alive (建議開(kāi)啟)
- 并發(fā)數(shù)是否足夠 (外網(wǎng)壓測(cè)要盡量開(kāi)啟更大的并發(fā))
- 服務(wù)端進(jìn)程數(shù)是否合理 (helloworld業(yè)務(wù)進(jìn)程數(shù)建議與cpu數(shù)相同,數(shù)據(jù)庫(kù)業(yè)務(wù)進(jìn)程數(shù)建議為cpu的四倍及以上)
- 業(yè)務(wù)自身性能 (例如是否使用了外網(wǎng)數(shù)據(jù)庫(kù))
HTTP keep-alive是什么?
HTTP Keep-Alive機(jī)制是一種用于在單個(gè)TCP連接上發(fā)送多個(gè)HTTP請(qǐng)求和響應(yīng)的技術(shù),它對(duì)于性能測(cè)試結(jié)果影響很大,關(guān)閉keep-alive后QPS可能成倍下降。
目前瀏覽器都是默認(rèn)開(kāi)啟keep-alive的,也就是瀏覽器訪問(wèn)某一個(gè)http地址后會(huì)將連接暫時(shí)保留不關(guān)閉,下一次請(qǐng)求時(shí)復(fù)用這個(gè)連接,用來(lái)提高性能。
壓測(cè)時(shí)建議開(kāi)啟keep-alive。
另外,如果不開(kāi)啟keep-alive壓測(cè),客戶端本地端口很快會(huì)被timewait狀態(tài)耗光,表現(xiàn)為總請(qǐng)求數(shù)超過(guò)一定數(shù)量(一般約2.8萬(wàn)左右),就會(huì)出現(xiàn)失敗的請(qǐng)求。
壓測(cè)時(shí)如何開(kāi)啟HTTP keep-alive?
如果是用的ab程序壓測(cè)需要加-k參數(shù),例如 ab -n100000 -c200 -k http://127.0.0.1:8787/
。
apipost需要在返回頭中返回gzip頭才能開(kāi)啟keep-alive(apipost的bug,參考下面)。
其它壓測(cè)程序一般會(huì)默認(rèn)開(kāi)啟。
為什么通過(guò)外網(wǎng)壓測(cè)QPS很低?
外網(wǎng)延遲很大導(dǎo)致QPS很低,是正?,F(xiàn)象。例如壓測(cè)baidu頁(yè)面QPS可能只有幾十。
建議內(nèi)網(wǎng)或者本機(jī)壓測(cè),排除網(wǎng)絡(luò)延遲影響。
如果一定要在外網(wǎng)壓測(cè),可以通過(guò)增加并發(fā)數(shù)來(lái)增加吞吐量(需保證帶寬充足)。
為什么經(jīng)過(guò)nginx代理后性能下降?
nginx運(yùn)行需要消耗系統(tǒng)資源。同時(shí),nginx和webman之間的通訊也需要消耗一定的資源。
然而,系統(tǒng)的資源是有限的,webman無(wú)法獲取到所有的系統(tǒng)資源,因此,整個(gè)系統(tǒng)的性能可能會(huì)有所下降是正?,F(xiàn)象。
為了盡可能減少nginx代理帶來(lái)的性能影響,可以考慮關(guān)閉nginx日志(access_log off;
),
開(kāi)啟nginx到webman之間的keep-alive,參考nginx代理。
另外https和http相比會(huì)損耗更多資源,因?yàn)閔ttps需要進(jìn)行SSL/TLS握手,數(shù)據(jù)加密解密,包的尺寸變大占用更多帶寬,這些會(huì)導(dǎo)致性能下降。
壓測(cè)如果用的是短鏈接(不開(kāi)啟HTTP keep-alive),每次請(qǐng)求都需要額外的SSL/TLS握手通訊,性能會(huì)大幅降低。建議壓測(cè)https開(kāi)啟HTTP keep-alive。
如何知道系統(tǒng)已經(jīng)達(dá)到性能極限?
一般來(lái)說(shuō)CPU達(dá)到100%時(shí)說(shuō)明系統(tǒng)性能已經(jīng)達(dá)到極限。如果CPU還有空閑說(shuō)明還沒(méi)達(dá)到極限,這時(shí)候可以適當(dāng)增加并發(fā)提高QPS。
如果增加并發(fā)無(wú)法提高QPS則可能是webman進(jìn)程數(shù)不夠,請(qǐng)適當(dāng)增加webman進(jìn)程。如果仍然無(wú)法提高考慮帶寬是否足夠。
為什么我壓測(cè)結(jié)果是webman性能低于go的gin框架?
techempower壓測(cè)顯示webman不管在純文本、數(shù)據(jù)庫(kù)查詢、數(shù)據(jù)庫(kù)更新等所有指標(biāo)都高于gin近一倍左右。
如果你的結(jié)果不一樣,可能是因?yàn)槟阍趙ebman中使用了ORM帶來(lái)了較大的性能損失,可嘗試 webman+原生PDO 與 gin+原生SQL 比較。
webman中使用ORM性能會(huì)損失多少?
以下是一組壓測(cè)數(shù)據(jù)
環(huán)境
服務(wù)器阿里云4核 4G,本地MySQL數(shù)據(jù)庫(kù),從10萬(wàn)條記錄中隨機(jī)查詢一條數(shù)據(jù)json返回,本機(jī)壓測(cè)。
如果使用原生PDO
webman QPS為1.78萬(wàn)
如果使用laravel的Db::table()
webman QPS降到 0.94萬(wàn)QPS
如果使用laravel的Model
webmanQPS降到 0.72萬(wàn)QPS
thinkORM結(jié)果類(lèi)似,區(qū)別不大。
提示
雖然使用ORM性能會(huì)有所下降,但是對(duì)于99%的業(yè)務(wù)來(lái)說(shuō)性能已經(jīng)嚴(yán)重溢出,如果你剛好是那1%也可以通過(guò)增加cpu或者服務(wù)器輕松解決。
我們應(yīng)該在開(kāi)發(fā)效率、可維護(hù)性、性能等多個(gè)指標(biāo)中找到一個(gè)平衡點(diǎn),而不是一味追求性能。
為什么用apipost壓測(cè)QPS很低?
apipost的壓力測(cè)試模塊有bug,如果服務(wù)端不返回gzip頭則無(wú)法保持keep-alive,導(dǎo)致性能大幅下降。
解決辦法返回時(shí)將數(shù)據(jù)壓縮并添加gzip頭,例如
<?php
namespace app\controller;
class IndexController
{
public function index()
{
return response(gzencode('hello webman'))->withHeader('Content-Encoding', 'gzip');
}
}
除此之外,apipost一些情況下無(wú)法打出滿意的壓力,這表現(xiàn)為同樣的并發(fā),使用apipost要比ab低50%左右的QPS。
壓測(cè)建議用ab、wrk或其它專(zhuān)業(yè)的壓測(cè)軟件而不是apipost。
設(shè)置合適的進(jìn)程數(shù)
webman默認(rèn)開(kāi)啟cpu*4的進(jìn)程數(shù)。實(shí)際上無(wú)網(wǎng)路IO的helloworld業(yè)務(wù)壓測(cè)進(jìn)程數(shù)開(kāi)成與cpu核數(shù)一致性能最優(yōu),因?yàn)榭梢詼p少進(jìn)程切換開(kāi)銷(xiāo)。
如果是帶數(shù)據(jù)庫(kù)、redis等阻塞IO業(yè)務(wù),進(jìn)程數(shù)可設(shè)置為cpu的3-8倍,因?yàn)檫@時(shí)需要更多的進(jìn)程提高并發(fā),而進(jìn)程切換開(kāi)銷(xiāo)相對(duì)與阻塞IO則基本可以忽略。
壓力測(cè)試一些參考范圍
云服務(wù)器 4核 4G 16進(jìn)程 本機(jī)/內(nèi)網(wǎng)壓測(cè)
- | 開(kāi)啟keep-alive | 未開(kāi)啟keep-alive |
---|---|---|
hello world | 8-16萬(wàn)QPS | 1-3萬(wàn)QPS |
數(shù)據(jù)庫(kù)單查詢 | 1-2萬(wàn)QPS | 1萬(wàn)QPS |
第三方techempower壓測(cè)數(shù)據(jù)
壓測(cè)命令示例
ab
# 100000請(qǐng)求 200并發(fā) 開(kāi)啟keep-alive
ab -n100000 -c200 -k http://127.0.0.1:8787/
# 100000請(qǐng)求 200并發(fā) 未開(kāi)啟keep-alive
ab -n100000 -c200 http://127.0.0.1:8787/
wrk
# 200 并發(fā)壓測(cè)10秒 開(kāi)啟keep-alive(默認(rèn))
wrk -c 200 -d 10s http://example.com