高效的磁碟存取,對於系統的效能可以說是相當重要的。因為磁碟設備,通常是整個系統當中最慢速的存取元件,只要存取速度不夠理想,對系統造成的傷害就很大。

如何提高系統中磁碟的存取效率,在計算機結構及作業系統領域中,都有很多的研究。例如,研究在作業系統中如何組織檔案在磁碟中的位置,以加速檔案存取的速度。在作業系統中,甚至連如何排程移動磁碟的讀寫臂、如何做預先的存取(Prefetching)以達到更高的存取效能,都有演算法探討相關的議題。

加速磁碟存取的最好方式:避免磁碟存取
如何提高磁碟的存取速度,可以說是從最低階的硬體到高階的作業系統,乃至驅動程式層級,全都有關。對大型的系統而言,更得考慮到整體的儲存設備架構。即使問題看似很大,對大多數的程式人來說,需要具備的基本觀念,做好基本功課,其實很簡單。

想要提高磁碟存取的速度,最好的方式莫過於避免存取磁碟。是的,磁碟I/O的存取,再怎麼快,跟記憶體的存取速度相較之下,效能的差距是以數量級衡量。

程式人在撰寫程式時,就必須意識到任何磁碟檔案的存取,對系統來說,都必須付出某種程度的代價,因而在執行磁碟存取動作時,需格外地留意:會不會做了大量的磁碟存取?存取太過頻繁?讀寫的檔案過大?

針對大量、頻繁的檔案存取,是否能利用有效率的檔案結構加以儲存呢?(例如以O(N)的效率搜尋檔案內容,速度就和O(logN)相差甚大)。倘若免不了要頻繁地存取,那麼最好考慮針對頻繁存取的檔案,於記憶體中製作快取(Cache),畢竟這兩者的存取速度,有著天壤之別。

萬不得已時,把最耗時的部分移至記憶體
當你發現系統的效能瓶頸,來自於特定檔案的頻繁存取時,最簡單又極具成效的方式,便是為這些檔案的存取,製作In-Memory的快取。可惜的是,即使在記憶體價格相當低廉的今天,相較而言,記憶體仍然是系統中比較昂貴的資源。

你沒有辦法把所有的東西都塞到記憶體中處理,所以仍然必須決定這昂貴的資源應用於何處,答案仍是──從瓶頸下手。

把最頻繁、最耗時間的檔案存取,移到主記憶體中進行:對檔案內容的讀取動作,直接從主記憶體取得;對檔案寫入的內容,同時寫到主記憶體及實體的檔案。快取可以說是效能的靈藥,如果確實找出瓶頸,就可以用最簡單的方式,大幅地提升效能。

太大、太多或太多層次的檔案結構,都會拖慢效能
無論如何,你總是無法將所有的檔案存取動作,全都交給快取處理。面對無法快取的檔案存取,落實一套規畫好的檔案結構,甚至是注意檔案被擺放的方式,都很重要。設計沒有效率的檔案結構,存取起來當然很慢。

此外,太大的檔案,意謂發生多個程序或執行緒並行存取的情況可能性將大為提高。在這樣的情況下,為了確保資料的一致性,免不了要鎖定檔案資源。只要同時存取的程序或執行緒數量一多,等待鎖定解除的時間也會拉長,於是這個檔案搖身一變,而成為了瓶頸。因此盡可能地保持數量多、長度短的檔案是比較好的策略。

而當檔案數目一變多,怎麼有效地擺放這些檔案,又成了另一個重點。有些程式人並不知道,在許多常見的作業系統上,倘若在單一目錄下擺放過多的檔案,會使得檔案存取的速度變慢。

這是因為作業系統中檔案系統設計的關係。作業系統會利用某種結構(例如Unix上的inode或Windows上的FAT/FAT32)記錄常見的樹狀檔案系統(意指形成樹狀的目錄、子目錄、檔案……),以及各目錄及檔案的屬性及資訊。

在應用程式中開啟一個檔案的過程,隱含著逐一地在這結構中找出相對應的目錄,搜尋出檔案路徑中相符的子目錄……,直到找到檔案資訊為止。在這過程中,倘若一個目錄下的子目錄或檔案數過多,便會造成搜尋速度遲緩(檔案數與搜尋時間的成長關係,則視檔案系統之不同,而所有差異)。

我也曾見過,單一個目錄中放置了數萬個,甚至超過十萬個檔案的系統。使用者及維護的資訊單位,只知道系統隨著時間越來越慢,卻不知道究竟是在那一個環節上出錯。

直到透過效能檢測工具,找出了效能低落的原因,竟然源自於讀取這個超大型目錄中的檔案,所引發的巨額時間消耗。

因此,當你需要管理為數眾多的檔案時,依據檔案系統的特性,適當地將檔案放置到分層的目錄下,形成單一目錄下不會超過一定個數的子目錄或檔案,就可以避免上述的問題。

例如256個,在大多數的檔案系統中,應該都只需要讀取目錄資訊一次,即可取得所有的子目錄及檔案資訊。

網站架構選哪一種,也會影響效能
網路存取的效能問題,就和檔案存取的效能問題很相像。會影響到網路存取效能的因素眾多,從網路本身的規格、硬體、驅動程式、Protocol Stack的實作、作業系統中的參數設定、應用層的通訊架構及協定,到應用程式的撰寫方式等,都會影響到。如果單看程式人負責的守備範圍,那麼大概就可以縮小範圍到應用層的通訊架構、協定的設計,以及應用程式的撰寫方式了。

例如,你開發的是一個影音分享網站,那麼便會面臨到一個重要的課題,就是究竟要選擇集中式、分散式,或者是點對點的架構。倘若使用點對點的架構,那麼伺服器所需的頻寬,相對於集中式的架構便少了許多。伺服器對外的網路速度,就不致於成為效能的瓶頸。

倘若採用集中式的架構,那麼倘若不能供給系統足夠的對外頻寬,那麼很容易使得系統使用者在下載影音檔時的速度緩慢。但是,這也不意謂著集中式的架構全無優點,集中式的架構容易管理(舉凡身分認證、權限管控),而實作複雜度也低。究竟適合那一種架構,最終還是要回歸到系統本身的特質而定。

HTTP 1.1已解決不少效能難題
除了架構會影響到網路效能的存取之外,設計不良的通訊協定也會造成網路存取的速度慢,或網路頻寬的浪費及擁塞。好比早期的HTTP 1.0通訊協定,並不支援續傳的功能,那麼當下載大檔案卻中途中斷時,就得重頭再來過,便會造成網路頻寬的浪費。

此外,由於HTTP 1.0協定是個無狀態(Stateless)的協定,這使得每次發送HTTP協定中的請求訊息(HTTP Request)時,都得重新在伺服器端及客戶端建立一個全新的TCP連線,而TCP連線的建立是個頗為耗時的動作。這兩個問題在HTTP 1.1中都有了改進。從上面的例子看來,我們可以了解設計不佳的通訊協定所造成的傷害。

在自行設計通訊架構以及通訊協定時,會面臨比較多的挑戰,畢竟設計一個有效率的架構及協定,並不是一件容易的事。大多數情況下,我們會在既有的通訊架構及協定下開發系統,如何在這些協定下獲得最高的效能,就存在更多程式人必備的基本觀念了。

《作者簡介》王建興
清華大學資訊工程系的博士研究生,研究興趣包括電腦網路、點對點網路、分散式網路管理、以及行動式代理人,專長則是Internet應用系統的開發。曾參與過的開發專案性質十分廣泛而且不同,從ERP、PC Game到P2P網路電話都在他的涉獵範圍之內。

相關閱讀:
高效的系統開發要領(1)制定量化效能目標,作為調整基準
高效的系統開發要領(2)找出最關鍵的效能瓶頸
高效的系統開發要領(3)當瓶頸在運算量時,先從程式下手
高效的系統開發要領(5)努力瘦身,輕鬆通過對外頻寬的瓶頸
高效的系統開發要領(6)伺服器運用頁面快取,加速效果驚人
高效的系統開發要領(7)把關資料處理細節,效能過關很簡單

熱門新聞

Advertisement