為了更精準地捕捉系統的效能瓶頸所在,我們會藉助效能測試的工具,協助診斷系統的效能。但找出系統效能的瓶頸,僅只是效能調校的第一課,而如何解除這個瓶頸則是第二課。
抓到拖慢效能的真正病因,才能對症下藥
不同類型的效能瓶頸,自然需要不同的方法改善。常見的效能瓶頸發生的來源,可能包括處理器計算量、磁碟存取、網路存取與資料庫存取。
當系統需要的處理器計算量太大,便會需要較多的系統執行時間,那麼運作自然顯得步伐緩慢。因為系統可能會連接各種I/O設備,其中最常見的,莫過於儲放檔案系統的硬碟。
當系統對檔案系統的存取需求過大時,也有可能為了等待硬碟存取,而拖慢執行速度,尤其磁碟的存取,速度往往都是比較慢的,當系統的瓶頸發生在磁碟存取時,拖垮系統效能的程度更高。相較於對磁碟的存取,網路的存取速度就更慢。
現在開發的系統中,有許多是透過網路為多個用戶端程式提供服務,除了受到頻寬的限制之外,倘若未有效處理來自用戶端同時發出的大量請求時,系統效能更可能一落千丈。
而資料庫由於是系統架構中最為集中化的組成,也最容易形成瓶頸。大量的資料存取,耗時耗工的SQL指令,都有可能造成資料庫存取龜速,同樣對系統效能造成很大的傷害。
當你透過效能量測工具,找到效能瓶頸所在後,應該要能夠知道這效能問題是如何引起,又究竟是屬於那一種類型的問題,是處理器運算過多?還是資料庫存取所導致?知道問題如何引起,才能夠進一步對症下藥。
熟悉軟體的組態設定,才能使系統在正確的效能假設下運作
在簡單介紹常見的症狀之前,我想先提一個重要的觀念。
許多程式人(包括我在內),對自己所採用的各種軟體元件(作業系統、Web伺服器、資料庫伺服器等)的組態設定,並不是很了解,也很少放太多的心力在那部分上面,因此遇到效能的問題時,只懂得將心力專注在自己所開發的軟體的效能調整上,費盡一切努力希望系統跑得越快越好。
殊不知,其實系統的效能表現,和自己所運用到的其他軟體元件的效能是息息相關,如果沒有調整這些軟體系統的組態,使它們的效能參數與自己的系統匹配,那麼整體搭配起來,即使該系統調整得再快,也有可能因為其他系統表現不彰,而讓整個運作相當慢。
所以,了解所運用的其他軟體系統,並且適當地根據情況加以設定。例如,在設定Tomcat時,它有一個Thread Pool,當收到來自用戶端的請求時,會從中取得一個Thread處理請求。
Thread Pool允許程式人透過參數設定它的容量。當Thread Pool中的Thread數目太少時,便有可能因為沒有額外的Thread服務請求,而必須等待其他的Thread服務結束後,才能夠服務這個請求。當這種情況發生時,對於用戶端來說,系統服務的時間便拖長了。
為此,我們會需要設定更大的Thread Pool,以提供更多的資源來服務請求。但另一方面,Thread Pool越大,會需要更多的作業系統資源,作業系統花費在排程的額外負擔也會更大,因此,必須在系統可能會需要同時服務的最大請求數量,以及系統所具備的資源二者之間權衡之下,找出一個理想的設定值。
不僅Web伺服器如此,作業系統、資料庫伺服器等,都有繁多的效能參數可供設定,不適當的參數,會使系統在不正確的效能假設下運作,最後導致不佳的效能表現。
縮短處理器運算時間方法一:尋求更好的演算法
當你發現某一段程式耗費大量的處理器時間,有幾個常見的可能。
首先,使用的演算法不夠好。最簡單的改善之道,便是尋求更好的演算法。除非是特定的演算問題,否則大多數會需要的演算法,在教科書中,都會有一定的介紹。
所以,拿出你塵封在書架上許久的演算法教科書,然後認真找找看吧。對於需要另行開發新演算法的問題,就試著逐漸改善自己的原始演算法。
縮短處理器運算時間方法二:善用快取暫存計算結果
第二,在程式中計算出其實不會變動,或很少變動的值,而這個計算既反覆卻又頗為耗時,這是很常見到的情況。
最簡單的例子,例如有個像是double sin(int x)的函式,它利用了泰勒展開式算出傳入參數x的三角函數sin()之值。這麼一來,每次呼叫sin(x)時,都需要花費不少的時間計算,但是實際上sin(x)值是恆常不變的。
為此,有人發明了查表法,針對有限的x的值域,建立一個sin(x)的表格。當想要取得x的sin()值時,便直接查表取得,完全不需要計算。如此一來,便只需要在系統初始化建立表格時,計算這個表格的內容,爾後需要取sin()值時,只需要查表,便可以節省可觀的處理器時間。
這種建表查詢的方式,可以運用在所有計算成本昂貴、但計算結果只和參數相關的應用之上。我們曾經找出過一個系統的效能瓶頸,竟然發生在每每重複計算一個使用者所具備的存取權限(Access Control List)。其實系統的存取權限幾乎不會在短期內有所變化,這個計算頗為昂貴,卻又大可不必,於是,建立一個表格儲存計算結果,只有在查詢不到時,才會重新計算使用者所擁有的存取權限列表,並置入表格中。如此一來,便能省去程式反覆計算的消耗。
你應該能夠發現,這種觀念和快取(Cache)已經很接近。我們通常用表格來記錄恆常不變的計算結果,然後利用快取,儲存即時性需求不那麼高的計算結果。
縮短處理器運算時間方法三:採用更高效的程式語言
如果耗時的動作已經用了夠好的演算法,也不滿足使用查表格或快取的先決條件,另一個解決的方式,便是採用更高效的程式語言。例如,對Java開發的系統而言,高計算量的動作,可以考慮JNI(Java Native Interface)的方式,以C/C++寫成原生的程式庫,讓Java語言呼叫。
對於高度處理器運算量的動作,以C/C++撰寫,在執行速度上還是占有優勢,因此,便能夠降低特定動作所需的執行時間。甚至對於一些本身就已經是C/C++撰寫而成的程式來說,如果使用組合語言撰寫,搭配最佳化的指令集,也有機會改善系統的執行效率。
縮短處理器運算時間方法四:添加硬體
最後,倘若軟體短期內已無他法,只能尋求添加硬體提供更多處理器計算量的方式解決。
必須要注意的是,並不是每個系統的架構,都允許透過添加硬體提高計算量,架構必須是可延展的(Scalable),例如架構本身就允許平行計算或分散式計算,才能夠利用添加硬體,達到擴充處理器計算能力的目的。
《作者簡介》王建興
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。
相關閱讀:
高效的系統開發要領(1)制定量化效能目標,作為調整基準
高效的系統開發要領(2)找出最關鍵的效能瓶頸
高效的系統開發要領(4)當瓶頸在檔案存取時,善用快取
高效的系統開發要領(5)努力瘦身,輕鬆通過對外頻寬的瓶頸
高效的系統開發要領(6)伺服器運用頁面快取,加速效果驚人
高效的系統開發要領(7)把關資料處理細節,效能過關很簡單
熱門新聞
2025-12-12
2025-12-12
2025-12-12
2025-12-12
2025-12-12
2025-12-12