壓測(cè)其實(shí)并非上線之前才進(jìn)行,而是在開發(fā)之初就開始準(zhǔn)備了。一般情況下在開發(fā)之前設(shè)計(jì)之時(shí)就應(yīng)該明白哪些接口會(huì)面臨高并發(fā)壓力,所以在開發(fā)時(shí)就要按照能夠承受高并發(fā)的標(biāo)準(zhǔn)進(jìn)行開發(fā)呜舒,比如盡量減少數(shù)據(jù)庫(kù)操作、采用連接池笨奠、邏輯盡量簡(jiǎn)單等等袭蝗。如果邏輯確實(shí)復(fù)雜唤殴,就要采用異步處理來(lái)解決。
壓測(cè)的目的
搞懂為什么要壓測(cè)到腥,這樣在壓測(cè)的時(shí)候才不會(huì)事倍功半朵逝,畢竟壓測(cè)一次的成本還是蠻高的。壓測(cè)其實(shí)有兩個(gè)目的乡范,一是測(cè)試應(yīng)用在高并發(fā)情況下是否會(huì)報(bào)錯(cuò)配名,進(jìn)程是否會(huì)掛掉;二是測(cè)試應(yīng)用的抗壓能力篓足,預(yù)估應(yīng)用的承載能力段誊,為運(yùn)維同學(xué)提供擴(kuò)容的依據(jù)闰蚕。
第一點(diǎn)很好理解栈拖,做好這一點(diǎn)就可以保證上線之后不出問(wèn)題了。解釋下第二點(diǎn)没陡,我們都知道就是架構(gòu)設(shè)計(jì)的再優(yōu)秀涩哟,代碼寫的再好,應(yīng)對(duì)高并發(fā)單實(shí)例始終是有限的盼玄。所以通常是在滿足第一點(diǎn)的前提下贴彼,再根據(jù)可能到來(lái)的高并發(fā)壓力來(lái)計(jì)算需要多少實(shí)例來(lái)承載,而這就需要我們壓出極限埃儿。
第一次壓測(cè)
接口開發(fā)完成之后就可以進(jìn)行第一次壓測(cè)器仗。這一次壓測(cè)可以簡(jiǎn)單壓一下,在本機(jī)進(jìn)行就可以童番。壓測(cè)的目的是檢查代碼在高并發(fā)下是否會(huì)報(bào)錯(cuò)精钮。另外,編譯型語(yǔ)言要觀察是否存在內(nèi)存泄漏剃斧,比如golang轨香。
因?yàn)楸緳C(jī)性能有限,一般來(lái)說(shuō)按照100幼东、200臂容、300、500進(jìn)程數(shù)進(jìn)行壓測(cè)根蟹,壓到500如果沒(méi)有報(bào)錯(cuò)就可以進(jìn)行疲勞測(cè)試脓杉,觀察內(nèi)存占用。
第二次壓測(cè)
一般來(lái)說(shuō)是不可能在線上進(jìn)行壓測(cè)的简逮,所以一般都是在仿真環(huán)境球散。所以這就對(duì)仿真環(huán)境提出了更高的要求,有條件的要保證仿真和線上配置一致买决。次之也要和線上成比例沛婴,這樣可以方便后續(xù)評(píng)估計(jì)算吼畏。
這一次壓測(cè)重點(diǎn)是壓極限。需要特別要注意嘁灯,這里的極限不是數(shù)據(jù)庫(kù)極限泻蚊,不是Redis極限,而是是指應(yīng)用服務(wù)器的極限承受能力丑婿。上面已經(jīng)說(shuō)了性雄,壓極限是為了給運(yùn)維同學(xué)提供擴(kuò)容的參考,所以我們要做的是壓到服務(wù)器的承受極限羹奉,看下到底能夠承受多大的并發(fā)秒旋。假設(shè)現(xiàn)在線上是雙實(shí)例8C8G,仿真雙實(shí)例4C4G诀拭。
比如說(shuō)我們我們壓出仿真的極限承受能力是1000迁筛,那么我們就可以預(yù)估線上能夠承受2000并發(fā)。比如我們預(yù)估接下來(lái)我們會(huì)迎來(lái)一次5000并發(fā)的沖擊耕挨,那么運(yùn)維同學(xué)就可以根據(jù)這些數(shù)據(jù)來(lái)評(píng)估出相應(yīng)的擴(kuò)容方案细卧。
壓測(cè)的常見(jiàn)步驟
比如第一次壓500的時(shí)候就出現(xiàn)了一些報(bào)錯(cuò),這時(shí)候就是遇到了第一個(gè)瓶頸筒占。當(dāng)解決第一個(gè)之后再繼續(xù)壓500贪庙,確認(rèn)解決了第一個(gè)瓶頸就可以繼續(xù)往上加,如此循環(huán)直到壓到服務(wù)器極限翰苫。
在這個(gè)過(guò)程中我們會(huì)遇到很多瓶頸止邮,沖破這一路瓶頸就像過(guò)關(guān)斬將一樣。
常見(jiàn)的瓶頸
php-fpm進(jìn)程數(shù)奏窑。一般php-fpm的進(jìn)程數(shù)是dynamic模式导披,也就是說(shuō)動(dòng)態(tài)調(diào)整。這種模式下無(wú)法應(yīng)對(duì)瞬時(shí)的高并發(fā)情況良哲,因?yàn)樗倪M(jìn)程數(shù)有個(gè)逐漸增加的過(guò)程盛卡。所以需要調(diào)整成static模式然后再根據(jù)服務(wù)器性能配置合理的進(jìn)程數(shù)。
負(fù)載均衡限額筑凫。比如阿里云的SLB最近就增加了配額限制滑沧,免費(fèi)版的實(shí)例只有5000的最大連接數(shù),3000的CPS和1000的QPS巍实。
壓測(cè)機(jī)性能限制滓技。這是一個(gè)比較容易忽略限制,所以我們?cè)趬簻y(cè)的過(guò)程中也要注意觀察壓測(cè)機(jī)的負(fù)載棚潦。如果達(dá)到這個(gè)瓶頸令漂,就要考慮采用多機(jī)壓測(cè)。
應(yīng)用服務(wù)器、Redis叠必、MySQL的最大連接數(shù)荚孵、CPU和內(nèi)存等等。這些都是比較嚴(yán)重的限制纬朝,所以一定要在壓測(cè)之前就搞清楚收叶。
如何來(lái)判斷遇到了什么瓶頸。
503 -- 服務(wù)不可用共苛,一般是負(fù)載均衡判没、nginx達(dá)到限制。
502 -- Bad Gateway隅茎,通常是應(yīng)用進(jìn)程掛掉了澄峰,或者進(jìn)程不夠用處理不過(guò)來(lái)。
500 -- 應(yīng)用故障辟犀,一般是應(yīng)用拋出了異常沒(méi)有正常響應(yīng)俏竞,比如達(dá)到Redis和MySQL的瓶頸。
一個(gè)不算常見(jiàn)的瓶頸
Redis帶寬踪蹬。阿里云的Redis帶寬限制大概是200M+胞此,如果數(shù)據(jù)量比較大,在高并發(fā)情況下很容易把帶寬打滿跃捣。目前的解決方案有兩個(gè),一是在存入Redis之前進(jìn)行數(shù)據(jù)壓縮夺蛇,在讀取Redis之后再進(jìn)行解壓疚漆。二是采用pb進(jìn)行存儲(chǔ),當(dāng)然這兩種方案我都還沒(méi)有真正使用過(guò)刁赦,等我解決了這個(gè)瓶頸再來(lái)更新娶聘。
一些壓測(cè)壓不出來(lái)的坑
現(xiàn)在大多數(shù)正式的項(xiàng)目都是前后端分離的,所以上述說(shuō)的其實(shí)都是壓后端接口甚脉,而有一種情況是壓根壓不出來(lái)的丸升,那就是接口調(diào)用數(shù)。作為后端開發(fā)牺氨,一定要搞清楚承受沖擊的前端頁(yè)面在加載的過(guò)程中會(huì)調(diào)用幾個(gè)接口狡耻,調(diào)用幾次。如果不搞清楚這些猴凹,在真實(shí)環(huán)境中后端服務(wù)器就可能承受比前端服務(wù)器還高的壓力夷狰,從而影響之前針對(duì)壓測(cè)數(shù)據(jù)做出的評(píng)估。針對(duì)這種情況郊霎,其實(shí)最好的方案就是在開發(fā)之時(shí)就跟前端約定好接口調(diào)用規(guī)則沼头,在接口設(shè)計(jì)和交互上進(jìn)行避免。
后序
前面就已經(jīng)提到過(guò)了,壓測(cè)一次的成本還是挺高的进倍。在這個(gè)過(guò)程中還要需要各方配合土至,所以,最好是在壓測(cè)之前就做好詳細(xì)的計(jì)劃猾昆,這樣才能事半功倍毙籽。