讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議134:推薦使用「望聞問切」的方式診斷性能 >

建議134:推薦使用「望聞問切」的方式診斷性能

「望聞問切」是中醫診斷疾病的必經步驟,「望」是指觀氣色,「聞」是指聽聲息,「問」是指詢問症狀,「切」是指摸脈象,合稱「四診」,經過這四個步驟,大夫基本上就能確認病症所在,然後加以藥物調理,或能還以病人健康身軀。

一個應用系統如果出現性能問題,不管是偶發性問題還是持久性問題,都是系統「生病」的表現,需要工程師去診斷,然後對症下藥。我們可以把Java的性能診斷也分為此四個過程(把我們自己想像成醫生吧,只是我們的英文名字不叫Doctor,而是叫做Trouble Shooter):

(1)望

觀察性能問題的症狀。有人投訴我們開發出的系統性能慢,如蝸牛爬行,執行一個操作,在等待它返回的過程中,用戶已經完成了倒水、喝茶、抽煙等一系列消遣活動,但系統還是沒返回結果!其實這是個好現象,至少我們能看到症狀,從而可以對症下藥。性能問題從表象上來看可以分為兩類:

不可(或很難)重現的偶發性問題

比如線程阻塞,在某種特殊條件下,多個線程訪問共享資源時會被阻塞,但不會形成死鎖,這種情況很難去重現,當用戶打電話投訴時,我們自己趕到現場症狀已經消失了,然後1個月內再也沒有出現過,當我們都認為「磨合」期已過,系統已經正常運行的時候,又接到了類似的投訴,崩潰呀!對於這種情況,「望」已經不起作用了,不要為了看到症狀而花費大量的時間和精力,可以採用後續提到的「聞問切」方式。

可重現的性能問題

客戶打電話給我們,反映系統性能緩慢,不需要我們趕到現場,自己觀察一下生產機就可以發現部分交易緩慢,CPU過高,可用內存較低等問題,在這種情況下我們至少要測試三個有性能問題的交易(或者三個與業務相關而技術無關的功能,或者與技術有關而業務無關的功能),為什麼是三個呢?因為「永遠不要帶兩塊手錶」,這會致使無法驗證和校對。

比如三個不同的輸入功能,都是用戶輸入信息,然後保存到數據庫中,但是三個交易的性能都非常緩慢,通過初步的「望」我們就可以基本確認是與數據庫或數據驅動相關的問題;若是只有一個交易緩慢,其他兩個正常,那就可以大致定位到一個面:該交易的邏輯層出現問題。

(2)聞

中醫上的「聞」是大夫聽(或嗅)患者不自覺發出的聲音和氣味,在性能優化上的「聞」則是關注項目被動產生的信息,其中包括:項目組的技術能力(主要取決於技術經理的技術能力)、文化氛圍、群體的習慣和習性,以及他們專注和擅長的領域等,各位讀者可能要疑惑了:中醫上「聞」的對象是病人,而為什麼這裡「聞」的對象卻是開發團隊呢?

我們這樣來思考該問題,如果是一個人(個體)生病了,找大夫如此處理是沒有任何問題的,但是如果是人類(群體)生病了,那如何追尋這個根源呢?假設人是上帝創造的,如果有一群外星生物說「人類都有自私的缺陷」,那是不是應該去觀察一下上帝?瞭解這個缺陷是源於他的習慣性動作還是技能缺乏,或者是「文化傳承」。對於一個Java應用來說,我們就是「上帝」,我們創造了他,給了他生命(能夠運行),給了他尊嚴(用戶需要它),給了他靈魂(解決了業務問題),那一旦他生病,是不是應該審視一下我們這些「上帝」呢?或者我們得自我反省一下呢?

如果項目組的技術能力很強,有資深的數據庫專家,有頂尖的架構師,也有首席程序員,那性能問題產生的根源就應該定位在無意識的代碼缺陷上。

如果項目組的文化氛圍很糟糕,組員不交流,沒有固定的代碼規範,缺乏整體的架構等,那性能問題的根源就可能存在於某個配置上,或者相互的接口調用上。

如果項目組已經習慣了某一個框架,而且也習慣了框架的種種約束,那性能的根源就可能是有人越過了框架的協約。

需要注意的是,「聞」並不是主動地去瞭解,而是由技術(人或應用)自行揮發出的「味道」,需要我們要敏銳地抓住,這可能會對性能分析有非常大的幫助。

(3)問

「問」就是與技術人員(締造者)和業務人員(使用者)一起探討該問題,瞭解性能問題的歷史狀況,瞭解「慢」產生的前因後果,比如對於業務人員我們可以咨詢:

性能是不是一直這樣慢,從何時起慢到不能忍受?

哪一個操作或哪一類操作最慢,大概的等待時間是多長?

用戶的操作習慣是什麼,是喜歡快捷鍵還是喜歡用鼠標點擊?

在什麼時間段最慢,業務高峰期是否有滯頓現象,業務低谷是否也緩慢?

其他訪問渠道,如移動設備是否也有效率問題?

業務品種和數量有沒有激增,操作人員是否大規模增加?

是否在業務上發生過重大事項或重要變更,當時的性能如何?

用戶的操作習慣有沒有改變,或者用戶是否自定義了某些功能?

而對於技術人員,我們就要從技術角度來詢問性能問題了,而且由於技術人員對系統瞭如指掌,可能會「無意識」地迴避問題,我們應該有技巧地處理這類問題,例如可以這樣來詢問技術人員:

系統日誌是否記錄了緩慢信息,是否可以回放緩慢交易?

緩慢時系統的CPU、內存、I/O如何?

高峰期和低谷時業務並發數量、並發交易種類、連接池的數量、數據的連接數量如何?

最早接到用戶投訴是什麼時候,是如何處理的,優化後如何?

數據量的增長幅度如何,是否有歷史數據處理策略?

系統是否有不穩定的情況,是否出現過宕機,是否產生過javacore文件?最後一次變更是何時,變更的內容是哪些,變更後是否出現過性能問題?操作系統、網絡、存儲、應用軟件等環境是否發生過改變?

通過與技術人員和業務人員交流,我們可以對性能問題有一個整體認識,避免「管中窺豹,只見一斑」的偏見,更加有助於我們分析和定位問題。

(4)切

「切」是「四診」的最後一個環節,也是最重要的環節,這個環節結束我們就要給出定論:問題出在什麼地方,該如何處理等。Java的性能診斷也是類似的,「切」就要我們接觸真實的系統數據,需要去看設計,看代碼,看日誌,看系統環境,然後是思考分析,最後給出結論。在這一環節中,需要注意兩點:一是所有的非一手資料(如報告、非系統信息)都不是100%可信的,二是測試環境畢竟是測試環境,它只是證明假設的輔助工具,並不能證明方法或策略的正確性。

曾經遇到過這樣一個案例,有一個24小時運行的高並發系統,從獲得的資料上看,在出現偶發性的性能故障前系統沒有做過任何變更,網絡也沒變更過,業務也沒有過大的變動,業務人員的形容是「一夜之間系統就變慢了」,而且該問題在測試機上不能模擬重現。接到任務後,馬上進行「望聞問」,都沒有太大的收穫。進入到「切」環節時,對大量的日誌進行跟蹤分析調試,最終鎖定到了加密機上:加密機屬於多個系統的共享資源,當排隊加密數據時就有可能出現性能問題,最終的解決方案是增加一台加密機,於是系統性能恢復正常。

性能優化是一個漫長的工作,特別是對於偶發性的性能問題,不要期望找到「名醫」立刻就能見效,這是不現實的,深入思考,尋根探源,最終必然能找到根源所在。中醫上有一句話「病來如山倒,病去如抽絲」,系統診斷也應該這樣一個過程,切忌急躁。

注意 性能診斷遵循「望聞問切」,不可過度急躁。