在一個系統出現性能問題的時候,很少會出現只有一個功能有性能問題(一個功能出現性能問題的情況非常容易解決,基本上不會花費什麼時間),系統一旦出現性能問題,也就意味著一批的功能都出現了問題,在這種情況下,我們要做的就是統計出業務人員認為重要而且緩慢的所有功能,然後按照重要優先級和響應時間進行排序,並找出前三名,而這就是我們要找的「准出頭鳥」。
「准出頭鳥」找到了,然後再對這三個功能進行綜合分析,運行「望聞問切」策略,找到問題的可能根源,然後只修正第一個功能的性能缺陷,再來測試檢查是否解決了這個問題,緊接著是第二個、第三個,循環之。可能讀者會產生疑問:為什麼這裡只修正第一個缺陷,而不是三個一起全部修正?這是因為第一個性能缺陷才是我們真正的出頭鳥,在我做過的性能優化項目中超過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%的功能,可能我們解決了這一部分,已經達到了用戶的預期目標,也就標誌著我們的優化工作可以結束了。
注意 解決性能優化要「單線程」小步前進,避免關注點過多而導致精力分散。