讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議136:槍打出頭鳥解決首要系統性能問題 >

建議136:槍打出頭鳥解決首要系統性能問題

在一個系統出現性能問題的時候,很少會出現只有一個功能有性能問題(一個功能出現性能問題的情況非常容易解決,基本上不會花費什麼時間),系統一旦出現性能問題,也就意味著一批的功能都出現了問題,在這種情況下,我們要做的就是統計出業務人員認為重要而且緩慢的所有功能,然後按照重要優先級和響應時間進行排序,並找出前三名,而這就是我們要找的「准出頭鳥」。

「准出頭鳥」找到了,然後再對這三個功能進行綜合分析,運行「望聞問切」策略,找到問題的可能根源,然後只修正第一個功能的性能缺陷,再來測試檢查是否解決了這個問題,緊接著是第二個、第三個,循環之。可能讀者會產生疑問:為什麼這裡只修正第一個缺陷,而不是三個一起全部修正?這是因為第一個性能缺陷才是我們真正的出頭鳥,在我做過的性能優化項目中超過80%的只要修正了第一個缺陷,其他的性能問題就會自行解決或非常容易解決,已經不成為問題了。

比如BBS系統,從用戶登錄到用戶瀏覽、發帖都非常緩慢,經過逐步篩選,確定登錄就是「出頭鳥」,需要著重解決,代碼如下:


class Login extends HttpServlet{

public void doGet(HttpServletRequest req, HttpServletResponse resp){

//從req中獲得用戶名和密碼

String userName=……;

String passwd=……;

//由登錄邏輯處理登錄

boolean loginSuccess=loginBiz.login(user, passwd);

if(loginSuccess){

//登錄成功,簽到

Checker.sign(userName);

}else{

//登錄不成功,記錄日誌

log.warn(userName+",登錄失敗!")

}

}

}


這是一個早期Web應用的典型驗證代碼,先驗證用戶是否登錄成功,然後決定是否向Session中寫入信息。在該BBS系統中,分析發現login和sign操作都非常耗時,那就首先跟蹤login,代碼如下:


class LoginBiz{

public void login(String_user, String_password){

//根據用戶名獲得用戶對像

User u=userDao.getUserByUser(_user);

return u!=null&&u.getPasswd().equals(_password);

}

}


追蹤到這裡,發現從數據中取出用戶對象的效率很低,但是數據庫的CPU、內存、I/O都沒有問題,而且沒有到達最大連接數。繼續追蹤下去,終於發現問題了:數據庫的版本和JDBC的版本不一致,雖然在進行所有的連接、執行SQL、斷開等操作時都沒有出現任何問題,但在多表的聯合查詢中速度非常慢。問題定位了,將其替換成數據庫匹配的驅動程序,登錄問題馬上得到解決,並且其他所有性能慢的問題都解決了,歸根結底其實都是數據庫驅動問題引起的。

解決性能問題時,不要把所有的問題都擺在眼前,這只會「擾亂」你的思維,集中精力,找到那個「出頭鳥」,解決它,在大部分情況下,一批性能問題都會迎刃而解,而且我們的用戶關注最多的可能就是系統20%的功能,可能我們解決了這一部分,已經達到了用戶的預期目標,也就標誌著我們的優化工作可以結束了。

注意 解決性能優化要「單線程」小步前進,避免關注點過多而導致精力分散。