天天看點

壓力測試你應該知道的幾個道理

1.從壓力測試說起

壓力測試的了解,xxx的性能10w/s,對你有意義麼?

    沒有那家賣瓜的會說自己家的不甜,同樣,沒有哪個開源項目願意告訴你在對它條件最苛刻的時候壓力情況是多少,一般官網号稱給你看的性能名額都是在最理想環境下的,毫無參考意義。

舉個栗子,redis官網壓測的例子,256位元組的讀速度11w/s,寫速度8.1w/s,都知道redis優點是多變的資料結構,string、List、hash、set、sortset,實際工作稍微複雜的環境往往都是各種結構混合使用,字元串長度各異,你需要的是真正在你的工作環境下,即:你混合使用的資料結構下,你的通路壓力下,你的字元串長度下redis的x響應性能。這個值往往跟官方公布的差異很大。我的經驗,我們是視訊行業,相對字元串長度較長,在壓縮序列化之後,主要使用String和List,性能在通路client=200-400左右,qps相應能到5w,超過這個client值,qps下降而且伺服器負載上揚,容易引起伺服器雪崩效應,這個5w,才是真正基于我們業務使用下redis的性能瓶頸。

我這個服務壓力2000tps,你覺得很牛逼?

       看着很牛逼對不對,好像tps值越高顯得能力越強一樣,其實很可笑,如果性能好隻是比這個,那寫一個1+1=2的程式估計是無敵了吧。具體問題要具體分析,你牛逼你要說明你牛逼在哪裡,在什麼條件下,什麼樣子的背景,才能說你的tps是多少,這樣才有意義。

反正線上沒出現過問題,我們撐得住,你确定?

       線上沒出現過問題,不代表流量不會增加,流量不會增加不代表業務不會複雜,業務複雜性能下降是很有可能的,沒有壓力測試做保證,出問題就是大問題。

壓力測試都是qa在做,有問題會回報給我,你的服務極限到底在哪裡?

       你應該關注一下qa是怎麼做壓力測試的,無論從服務的角度還是從個人發展的角度。qa隻能給你測試結果,不會告訴你性能瓶頸在哪裡。

2.壓力測試到底要關注什麼

壓測不是玩笑,你的4個9的名額呢

       好的服務都會有一項名額,叫4個9,即99.99%得服務可靠性。這是衡量一個服務是否優秀的普世标準,壓力測試的好壞最直覺的影響4個9的保障。壓力測試就是用來確定服務的穩定,給出服務穩定極限條件。穩定指的是服務負載,cpu使用率,接口的響應時長,網絡的延遲,結果準确性等等都在你的标準之内。而這些名額又互相影響。

條件,用盡量多的已知去推測未知,模拟仿真,你要做的預測未來

       硬體條件:伺服器cpu核數、記憶體大小、網絡條件、同主控端下其他服務影響,軟體條件:虛拟通路使用者數、gc的穩定程度,響應時長要求,第三方依賴的可用程度、jdk的不同版本等都會嚴重影響壓力測試的結果,造成你的壓測結果上線之後達不到逾期。如果這些條件不注意,很可能你壓測時按照達标條件tps=1000,其實線上tps才500的時候,服務已經崩潰了。壓測的時候,最好保障壓測環境與線上一緻。你的結果才更有意義。

3.你想要的到底是個什麼東西

       tps隻是結果,虛拟使用者數,線程數,平均響應時長,錯誤數,90%的平均響應時長,伺服器負載,結果準确性盡量用越來越多的點來評估你的服務。

tps:服務處理的吞吐量,每秒響應請求的數量,tps是壓力測試最直覺的結果,是衡量服務性能的一個結果性名額,一般說壓力測試性能值就是tps值。最淺顯直白的了解,統計access日志每秒的總數就是那一秒的tps值。

錯誤數:一般服務壓力測試的時候是不允許出現錯誤的,即錯誤數:0%,但是複雜條件下,有的服務是允許出錯率不超過x%的,看服務而定。

平均響應時長:移動網際網路時代,你讓一個使用者打開app等你1s,使用者早就跑了,打開app立刻看見内容是最起碼的要求,一般好的app接口相應時間都是毫秒級别的,但是不同的場景不同的要求,我的上一家公司要求平均相應時長在20ms以内。可是上上家公司的算法接口,平均相應時長在100ms,不同的服務不同的要求,你需要找到适合你自己的要求。

90%的平均響應時長:jmeter學來的,表示90%的事務,伺服器的響應都維持在某個值附近。比如有三個時間:1秒、5秒、12秒,則平均時間為6秒,而另外一種情況:5秒、6秒、7秒,平均時間也為6秒,顯然第二種比第一種要穩定多了。是以,我們在檢視平均事務響應時間的時候,先看整體曲線走勢,如果整體趨勢比較平滑,沒有忽上忽下的波動情況,取“Average Time”與“90 Percent Time”都可以,如果整體趨勢毫無規律,波動非常大,我們就不用“Average Time”而使用“90 Percent Time”可能更真實些

結果準确性:多線程下通路下結果的正确性。這個在壓測的時候往往容易被忽略。這個需要你在壓力測試的時候抽查通路接口,檢視結果是否正确,曾經碰到過qa測試通過的接口,上線之後發現傳回結果不正确,内網回測正确,後來内網壓力測試的時候成功複現,是由于使用了不安全的多線程代碼導緻的,其實壓測的時候抽檢視一眼,很容易看出來。

線程數:這個名額不在各大壓力測試工具監控之内,但是這其實是壓力測試非常重要的服務名額。根據經驗,好多時候服務崩掉的時候,線程數已經滿了,好多時候應用伺服器的線程在某個範圍之内,服務是最健康的狀态,超過某個範圍,服務處于不穩定狀态,處于有點網絡抖動延遲都容易崩潰的臨界點,是以熟悉這個值,你就心裡清楚你的服務目前在什麼狀态下。

虛拟使用者數(并發線程數):好多人容易把tps和虛拟使用者數搞混,虛拟使用者數表示目前正在通路你服務的使用者數,就是說壓力測試工具啟動多少個線程來不停通路你的接口。但是實際上,哪個使用者會像瘋狗一樣瘋狂一直不間斷的通路的你接口,對使用者來說,通路你的接口,點進去看内容,好久不再通路才是常态(專業術語叫思考時間),可是這個值的大小,嚴重影響tps的值。那這個值多少合适呢?我知道的有2種做法,一種是求得tps的最大值,在壓力測試的時候虛拟使用者數不可測,那幹脆不管,我就管好我服務的tps吞吐量,服務的吞吐量極限就是我的真實極限。做法就是找一個tps最高時的虛拟使用者數,記做壓力測試的虛拟使用者數名額,當然,這有個嚴重的問題,做過壓力測試的就知道,有的服務虛拟使用者很低時tps很高,但是虛拟使用者一但稍有提升,性能下降的非常快,怎麼彌補這種情況呢,政策是補區間,得到最好tps的虛拟使用者之後,在這個虛拟使用者數之上加減某個值(例如30),得到3個壓力測試結果,3個壓力測試結果的趨勢作為服務的性能名額。第二種是估算,目前服務的tps是多少,用壓測工具可以得到達到目前tps的并發線程數是多少,但這個值肯定也隻是一個估計值而已。

       多說一句,這個值為什麼又可以不去管它:其實真正線上流量大的時候經常會有一種現象:服務直接重新開機撐不起來目前流量,調整前端流量配置設定(部分nginx摘除重新開機server等做法),慢慢啟動就可以支援起線上流量,再打開所有流量,發現server又可以支援沒問題了(ps:是以nginx有一個流量緩增的收費子產品就是幹這個的),但是慢慢啟動線上流量和一次打過來線上流量,其實在同一時刻虛拟使用者數是差不多,斯以為這種現象是因為服務剛啟動時流量全打過來時需要建立的可複用複用對象和線程很多,容易造成了服務的不穩定,那麼其實壓力測試時虛拟使用者數重要麼?它真的是不可代替的麼?其實虛拟使用者數隻是用來探測服務性能的一個表現的總結而已,服務真正的健康情況其實反映線上程數,響應時長,伺服器負載,性能瓶頸點(比如事務或者鎖)等等,而虛拟使用者數隻是這些健康極限情況的表象總結而已。就是說,當壓力測試總結的虛拟使用者數在某一個範圍值tps達到多少,其實内在真正描述的是在這個虛拟使用者時,由于線程數是多少,負載是多少,平均相應時長是多少,線程數是多少,gc穩定程度是多少達到了tps值是多少。

4.面試總問的jvm調優到底是要幹什麼

       請注意,jvm調優,調的是穩定,并不能帶給你性能的大幅提升。服務穩定的重要性就不用多說了,保證服務的穩定,gc永遠會是java程式員需要考慮的不穩定因素之一。複雜和高并發下的服務,必須保證每次gc不會出現性能下降,各種性能名額不會出現波動,gc回收規律而且幹淨,找到合适的jvm設定。詳細了解jvm的話請看神書《深入了解java虛拟機》。說些題外話,面試發現,jvm調優很多人都沒有經驗,有人甚至懷疑這東西真正是否有用,有的公司統一jvm的設定貫穿所有服務。其實隻是沒碰到生産條件複雜的情況而已,舉個簡單例子:我曾經的公司,碰到過服務運作超過14h直接當機的問題,頭天下午壓測,第二天上午服務自動重新開機了,按照當時習慣,新服務需要壓力測試滿12h,原則上我的服務通過測試,由于測試環境複雜,所有開發都可以登陸而且腳本很多,qa認為可能是有腳本誤殺了,但是當時離上線deadline時間還早,于是決定再壓力一次,成功複現,最後檢視jvm發現每次fullgc之後o區總是會多一點,jmap列印記憶體棧發現char對象使用逐漸增大,最後撐滿記憶體, 最後定位到調用JNI發生記憶體洩露,解決了這個問題。這隻是簡單的一次,在那家公司,由于服務偏算法而且流量很高,碰到過很多這種問題。還有一次,壓力測試loadrunner圖像顯示每隔一段時間的點上響應時間立刻下降,過2s又恢複正常,規律性很強,通過jstat發現頻繁生成大對象直接進入老年代,老年代很快撐大觸發full gc回收,回收時間過長造成服務暫停明顯,立刻反應到壓測的響應上。解決的辦法是調大年輕代,讓大對象可以在年輕代觸發yong gc,調整大對象在年輕代的回收頻次,盡可能保證大對象在年輕代回收,減小老年代縮短回收時間,服務果然穩定下來。當時這麼調整下來會有一點性能損失,基本可以忽略不計,但是提升了服務的穩定性,這才是這次jvm調優最重要的。

5.常用的壓力測試工具及指令

loadrunner,jmeter,自寫jar包,tcpcopy等。

       壓力工具,大同小異,用什麼都行,tcpcopy是拷貝線上流量,對于已有接口和服務做壓力測試是個神器,jmeter和loadrunner是壓力測試工具,loandrunner壓測結果更詳細可視化不過笨重收費而且需要很多客戶機,jmeter相對是平民版的loadrunner,勝在免費。之前也有由于資料需要實時從資料庫查詢,自己寫http的client,就需要輔助一些shell和awk指令統計相應名額。

       jmap,jstack,jstat,詳細的講解推薦《深入了解java虛拟機》,其實不神秘但是特别實用,jstat檢視記憶體回收概況,實時檢視各個分區的配置設定回收情況,jmap檢視記憶體棧,檢視記憶體中對象占用大小,jstack檢視線程棧,死鎖,性能瓶頸,某個線程使用cpu過高導緻服務整體慢等都可以通過在這些指令輔助linux指令看出來。

top,vmstat,sar,dstat,traceroute,ping,nc,netstat,tcpdump,ss等等具體請百度。

       你的服務是跑在linux系統上的,是依賴第三方服務出問題了?是受别的服務影響還是自己利用資源過高?是網絡抖動了?是網卡滿了麼?是cpu性能不夠麼?是寫入磁盤瓶頸了?核心資料交換頻繁?負載變高了?都需要linux指令才能看出來。

6.性能診斷到底難在哪裡?

       收到服務報警了,怎麼辦?列印的log日志都是連接配接不上memcache,難道是memcache的問題,手動用戶端連接配接memcache沒問題,難道是網絡的問題,測試網絡延遲很低,那到底怎麼了?

其實服務類似于人體,有的人感冒的時候鼻子通氣嗓子疼,有的人頭疼,有的人流清涕,有的人流黃涕,對症下藥要治标治本。沒有什麼統一的答案,這就展現了經驗的重要性。舉個栗子:某天晚上突然收到報警,vpn登陸發現服務還正常傳回,暫時沒有報錯,但是負載明顯升高,resin線程數飙升到1000多(正常情況下該服務高峰期線程數500-700),cpu使用率偏高,排查:1.通路量激增?統計發現并沒有。2.網絡狀況異常?通過通路伺服器發現也沒有,稍微慢些是因為負載稍高。3.程式有瓶頸?列印記憶體棧線程棧都沒發現4.受其他同宿主服務影響?檢視監控發現并沒有。仔細觀察發現流量稍有波動但是不明顯。為什麼負載高呢?最後排查發現是前端nginx帶寬滿了,帶寬擁堵造成代理的後端服務無法及時傳回資料,後端服務的句柄數擁堵造成伺服器負載升高,伺服器負載升高又使線程數和cpu使用率升高,造成服務的個别通路響應時長過長,觸發報警。再嚴重些估計就會造成連接配接memcache逾時,log打出連接配接memcache錯誤的日志。蝴蝶效應而已。想要快速抓住重點,其實跟醫生一樣,就需要你對服務足夠了解,平時多關心服務狀态而且經驗真的很重要。

7.到底是加機器還是優化服務?

       成本,加機器是一種成本,優化服務也是一種成本,很有可能你的服務很多依賴第三方,推動他們符合你的要求也是一種溝通成本,很多時候,老闆的思路永遠在于成本,如果他認為服務有很大的優化空間,那你找他加機器他多半是不會同意的,是以這種要資源的事情,請考慮成本,也有一個問題,大公司往往會哭的才有奶吃,這也很現實,反正歸根到底,對于我們這些搞服務端的來說,成就感不就應該是把硬體伺服器資源壓榨到底麼?

原文位址:https://sunjia-704471770-qq-com.iteye.com/blog/2282141

繼續閱讀