1. 程式人生 > 其它 >硬碟的效能特徵

硬碟的效能特徵

  本文長度為2200字,建議閱讀3分鐘

  本文為你分析硬碟的效能特徵。

  我們都知道記憶體比硬碟要快得多,大概能快出一兩個數量級(價格也要貴這麼多)。不過,硬碟的問題並不只是訪問速度慢。

  硬碟不適合做頻繁小量訪問

  所謂頻繁小量訪問,是指運算過程中每次獲取的資料量很小,而讀取的次數很多。對於記憶體,每次取10位元組、取1000萬次、總共訪問1億位元組;和每次取1000萬字段、取10次、也訪問1億位元組;這兩者耗時是差不多的。記憶體訪問資料的最小單位就是位元組,無論怎麼做,最後涉及到的位元組數是一樣的。

  但硬碟的機制完全不同,在硬碟中資料是按扇區存放的,資料訪問的最小單位是扇區(一般是512位元組),也就是說從硬碟上讀1個位元組和讀512位元組的時間幾乎一樣的(記憶體複製時間相對於硬碟時間忽略不計了)。這樣,每次取10位元組取1000萬次,和每次取1000萬字節取10次,訪問量一樣,但耗時就可能會有巨大的差異,前者可能會多取很多無用的資料。

  實際情況還要更惡劣一些,我們常常直接使用作業系統中的檔案儲存資料,而大部分檔案系統的讀取單位是簇,預設大小一般是4K,比512位元組要大8倍。而且,讀取硬碟是一個複雜的動作,不象記憶體那樣執行一條CPU指令就可以讀取,訪問硬碟需要一系列的動作來啟動硬碟控制器並確定讀取位置,讀取1000萬次就要執行1000萬次這樣的動作,當然一次讀1000萬字節時也會涉及較多次的磁碟動作(1000萬字節會在很多扇區中),但總次數仍然會少得多,批量不頻繁讀取的效能就會遠遠好於頻繁小量讀取。

  不連續的隨機訪問是罪魁

  不過,我們在上述結論中用了“可能”二字,而沒有用肯定的語氣,這是因為還要考慮資料儲存是否連續。如果要訪問的資料在硬碟上是連續儲存的,那取1000萬次10位元組也不會很慢,因為後面的10位元組已經在前面讀出的扇區裡面而不必再讀,硬碟控制器以及作業系統都有快取功能,實際硬碟讀取次數並沒有那麼多,結果的效能相差也不會非常大。所以我們還要在"頻繁小量"前面加上“隨機”這個定語,也就是讀取的內容不連續,這時候,前面讀出的扇區取出需要的部分外,其它內容和後面要訪問的資料沒有關係,只能浪費掉,而且後面再訪問又要再次讀,”可能“就會變成”肯定“了。

  對於目前仍在大量採用的機械硬碟,隨機訪問還存在磁頭跳動問題,也就是硬碟指標中的平均尋道時間。尋道是個非常慢的機械動作,比讀一個扇區要慢得多得多。這樣,即使每次讀出扇區(簇)都沒有任何浪費,在隨機訪問時的尋道成本卻可能超過讀取本身。使用機械硬碟時要特別注意避免隨機頻繁小時訪問。

  固態硬碟的情況要好一些,它沒有尋道的機械動作了,這樣在隨機讀取時也沒有尋道時間問題。不過,儘管固態硬碟並不是按扇區形式儲存資料,作業系統仍將它模擬得和機械硬碟類似,必須按某個基本單位(簇)讀寫,這樣,隨機的頻繁小量(小於簇)訪問g還是會有前述的低效問題。對於許多需要隨機訪問小量資料的運算,簇(扇區)這個單位太大了。

  並行和併發導致隨機訪問

  那麼,對於只需要連續批量訪問的運算(比如遍歷彙總或查詢),使用硬碟時的效能是否就只是其本身訪問速度決定的呢?

  對於單執行緒或單任務的運算基本上是這樣。但現在研究高效能運算時顯然不可能不考慮並行運算,而且許多運算服務也需要支援多併發。並行和併發運算會使原本可以連續訪問的硬碟資料一定程度變成隨機訪問,原因很簡單:多執行緒實際上在共享同一套硬碟,不同執行緒的訪問請求顯然不會連續,硬碟要同時響應這些請求就會發生跳動,也就是隨機訪問了。

  對於機械硬碟這個後果常常很嚴重,如果執行緒之間切換頻繁,就會導致頻繁的尋道動作,結果就會發生多執行緒反而比單執行緒慢的現象。而有些單任務時效能尚可的場景,一旦併發了效能就會急劇下降。一個補救的辦法是加大讀資料的緩衝區,每個執行緒每次讀出的資料足夠多且連續,這樣能使尋道時間佔比變小而感覺不明顯。但同時也會加劇記憶體佔用,執行緒越多對記憶體需求越大。固態硬碟就好得多,緩衝區達到簇(扇區)的規模就可了。

  有點類似的場景是列式儲存,資料是按列連續存放的,需要多列計算時,即使單執行緒也會發生硬碟隨機訪問現象,涉及列較多時就未必會比行存有優勢,多執行緒還會進一步加劇這個問題。在機械硬碟上用列存時要特殊注意這個問題,不一定總能提高效能。

  外存運算需要採用不同的演算法

  由於硬碟的這些特徵,有些運算從記憶體換到外存時會採用完全不同的方法,效能下降的程度也不是簡單按比例做乘法。

  比較典型的是JOIN運算,對於外來鍵式1:N的JOIN,如果資料全部在記憶體中,可以使用針對外來鍵維表主鍵做HASH索引,遍歷事實表時用索引直接可以找到維表的相應記錄,事實表有多個外來鍵指向不同維表時也只要遍歷一次就可以全解析。但如果維表過大而不能裝入記憶體時就不能採用同樣的演算法了,因為硬碟無法支援隨機頻繁小量的訪問,而訪問維表記錄恰恰是這種運算,強行使用這種方案的效能會惡劣到還不如把資料先排序再來歸併的地步。外存大表JOIN時要按鍵值(的HASH值)分段,每段都足夠小可以裝入記憶體做JOIN,這種方法一次只能解析掉一個關聯,事實表指向多個外來鍵大維表時就要做多輪解析,運算量比記憶體JOIN大得多。

  單機記憶體不足時還可以利用叢集來避免複雜的外存運算。網路本身的延遲和硬碟差不多,通過網路獲取叢集機的記憶體資料時,單位資料量的訪問效能不會比硬碟好多少,但卻可以利用記憶體的隨機訪問能力和併發能力。不過網路和硬碟類似,每次啟動一個網路連線的消耗較大,也不合適頻繁小量的訪問,要把多次獲取資料的請求和返回結果積累起來一起傳輸。用這種方法做大維表JOIN,比記憶體計算麻煩,但比外存運算還是簡單很多,仍然可以一次性解析掉多個關聯。