最近看了zee老弟的文章,通過分析網(wǎng)絡(luò)流量來分析性能問題,于是也想寫一篇。
我早期做性能測試,大概在99年。給一個(gè)銀行做性能測試,因?yàn)槠渲泻艽蟮囊粋€(gè)部分是我們開發(fā)的。于是自己寫了一個(gè)程序,來給后臺(tái)系統(tǒng)加壓。
大概在2001年,我們做了兩外一個(gè)系統(tǒng),跑在aix上面,性能很差,我?guī)烷_發(fā)團(tuán)隊(duì)去看一下問題,結(jié)論是調(diào)度過度,架構(gòu)不合理(組件模塊劃分的過細(xì))。調(diào)優(yōu)之后,性能提升了大概100倍。后來去給客戶做poc,客戶還嫌慢,說明調(diào)優(yōu)還不到位。再后來又做了一次調(diào)優(yōu),性能才正常。所謂的正常,就是跟使用tuxedo相比,基本上性能持平,一個(gè)數(shù)量級(jí)。
從性能問題來看,大概分成幾種情況:1,網(wǎng)絡(luò)帶寬問題;2,某個(gè)節(jié)點(diǎn)處理能力(就是tps差)不行;3,流量配置不合理;4,鏈路設(shè)計(jì)問題。
先說網(wǎng)絡(luò)帶寬問題。以前的老系統(tǒng),特別是銀行的,一般情況下oltp都不會(huì)有帶寬問題,因?yàn)楦鶕?jù)oltp的標(biāo)準(zhǔn),一個(gè)請(qǐng)求包在1-2k,響應(yīng)報(bào)文在4k之內(nèi),除非線路很差,一般都不會(huì)有。從現(xiàn)在的情況來看,更不會(huì)有網(wǎng)絡(luò)問題。
我遇到一次網(wǎng)絡(luò)問題,是由于病毒占用了大量的帶寬,阻塞了。特殊的情況在于報(bào)表下載。如果所有的用戶,在某個(gè)時(shí)間點(diǎn)上都下載報(bào)表呢?也會(huì)有擁堵。
實(shí)際上,只要根據(jù)tps和一次請(qǐng)求占用的流量大小,來計(jì)算一下,就知道整個(gè)的帶寬是不是有問題。
比如,一次請(qǐng)求的數(shù)據(jù),假設(shè)是50k,tps是1000,那么帶寬需求是:1000*50k=50M。還要考慮上行帶寬還是下行帶寬,請(qǐng)求是上行帶寬。
此外就是一些網(wǎng)絡(luò)上傳輸?shù)膱D片很容易占用帶寬。
再說流量分配不合理。某個(gè)客戶有多個(gè)節(jié)點(diǎn),使用nginx來做負(fù)載均衡,由于配置錯(cuò)誤,導(dǎo)致90%以上的流量都分配到其中一個(gè)節(jié)點(diǎn),導(dǎo)致性能嚴(yán)重不達(dá)標(biāo)。這種就需要使用全鏈路分析,看兩個(gè)不同節(jié)點(diǎn)的cpu占用、帶寬,很容易發(fā)現(xiàn)問題。流量分配不合理,主要是配置問題。因此全鏈路跟蹤監(jiān)控工具非常重要。
近些年,由于系統(tǒng)越來越復(fù)雜,已經(jīng)從C/S、B/S架構(gòu)的兩層結(jié)構(gòu),發(fā)展到三層結(jié)構(gòu)、多層結(jié)構(gòu)。
在業(yè)務(wù)處理的每一層,如果出現(xiàn)問題,都可能出現(xiàn)性能瓶頸,所以,我們首先要定位,是哪一層出現(xiàn)了問題。
鏈路設(shè)計(jì)問題。有時(shí)候,由于應(yīng)用系統(tǒng)設(shè)計(jì)不當(dāng),導(dǎo)致產(chǎn)生了很多多余的鏈路。比如可以使用三次通訊來解決的問題,結(jié)果使用了5次,多出來的兩次很容易造成錯(cuò)誤和性能問題。當(dāng)然性能測試只能夠發(fā)現(xiàn)問題,解決問題還要看設(shè)計(jì)鏈路的人。
這里面就涉及到一個(gè)問題:架構(gòu)。網(wǎng)絡(luò)架構(gòu)、系統(tǒng)架構(gòu)、IT架構(gòu)等等。話題太大,就不展開贅述了。
最后,我們看節(jié)點(diǎn)處理能力問題。其實(shí),節(jié)點(diǎn)又分成很多種類,比如存儲(chǔ)、比如數(shù)據(jù)庫。這一類的問題,一個(gè)要看數(shù)據(jù)庫的配置和資源情況,另外一個(gè)就要看表結(jié)構(gòu)、索引,重要的一點(diǎn)是程序。
數(shù)據(jù)庫問題,常用的是看資源是否占滿,比如io,比如cpu等資源是否過高。如果不高,但是又很慢,大多數(shù)是程序和結(jié)構(gòu)問題。
最后看代碼,也就是應(yīng)用程序。應(yīng)用程序優(yōu)化,往往是系統(tǒng)的核心,絕大多數(shù)的性能問題,都是由于代碼編寫不當(dāng)引起的。
從我自己的經(jīng)驗(yàn)來看,主要是幾大類:
1,錯(cuò)誤的數(shù)據(jù)結(jié)構(gòu)和算法。
某個(gè)項(xiàng)目,做了一個(gè)插入操作,結(jié)果花費(fèi)了一分鐘。我仔細(xì)看了一下代碼,其實(shí)算法并不是很復(fù)雜,就是在數(shù)據(jù)庫中構(gòu)建了一個(gè)tree,然后把某個(gè)節(jié)點(diǎn)插入。
但是很慢。本質(zhì)的問題在于,程序員把數(shù)據(jù)庫當(dāng)作內(nèi)存來使用。內(nèi)存的訪問速度很快,數(shù)據(jù)庫查了幾個(gè)量級(jí)。
所以使用錯(cuò)誤的數(shù)據(jù)結(jié)構(gòu),是很多問題的核心。這種情況就需要修改架構(gòu)和算法才能夠解決。
2,算法問題。
另外一個(gè)項(xiàng)目,也是操作很慢。去看了一下,沒有架構(gòu)問題。但是,有很多循環(huán)嵌套。關(guān)鍵是,在循環(huán)里面去訪問database。
千萬不要在循環(huán)里面去訪問db,幾乎是百分之百的慢。
循環(huán)嵌套。就是多層循環(huán),里面還嵌套數(shù)據(jù)庫訪問,程序員是想作死。
3,block和輪詢。
block,阻塞和輪詢,是我們?cè)L問資源的兩個(gè)方式。block的問題會(huì)造成程序掛起,但是掛起并不消耗cpu,但是會(huì)占住一個(gè)線程/進(jìn)程。
輪詢很快,但是頻繁的輪詢會(huì)導(dǎo)致cpu上升。
所以要評(píng)估你的算法,當(dāng)訪問資源的時(shí)候,是使用block還是輪詢。
好像這一直是個(gè)問題,需要大量編碼經(jīng)驗(yàn)才能解決。
這也就是說,為什么沒有大量的編碼經(jīng)驗(yàn),吹噓做架構(gòu)師,很容易犯低級(jí)錯(cuò)誤。
4,資源忘了釋放。
這是很多板磚程序員容易犯的錯(cuò)。
5,分清楚系統(tǒng)調(diào)用和一般的調(diào)用。
系統(tǒng)調(diào)用,system call,會(huì)調(diào)用操作系統(tǒng)的核心,訪問核心資源。所以,你看起來是一個(gè)函數(shù),但是這個(gè)函數(shù)會(huì)導(dǎo)致你的系統(tǒng)很慢。
當(dāng)然現(xiàn)在使用的語言遠(yuǎn)比c這樣原始的語言高級(jí),使得程序員分不清系統(tǒng)調(diào)用和一般函數(shù)。
經(jīng)常遇到的問題是,內(nèi)存分配。當(dāng)你頻繁訪問內(nèi)存,一些算法是從操作系統(tǒng)的堆來申請(qǐng)內(nèi)存的,導(dǎo)致系統(tǒng)很慢,而且會(huì)產(chǎn)生很多內(nèi)存碎片。
所以分清楚系統(tǒng)調(diào)用和一般函數(shù),非常重要,盡量避免使用系統(tǒng)調(diào)用,特別是頻繁的調(diào)用。
6,程序執(zhí)行效率不高。
這個(gè)其實(shí)有很多算法,比如循環(huán)展開等等。你需要去了解編譯器、cpu的指令序列是如何工作的。
cpu最怕的指令是jump,就是程序里面的循環(huán)和判斷(if-else)。
如果知道這些,解決大多數(shù)性能問題應(yīng)該不困難。
推薦閱讀
本文內(nèi)容不用于商業(yè)目的,如涉及知識(shí)產(chǎn)權(quán)問題,請(qǐng)權(quán)利人聯(lián)系SPASVO小編(021-60725088-8054),我們將立即處理,馬上刪除。