前言
因為SSD有著諸多與傳統機械式硬盤不同的特點,而且這些特點導致了SSD在實際使用中的性能和壽命與其使用方法緊密相關。所以并不是說買來一塊非
常牛X的SSD就萬事大吉了。另一方面,SSD的性能并不像機械式硬盤那樣比較穩定(浮動范圍小),而是呈現出一種離散的特點(浮動范圍大),最佳狀態與
最差狀態相差甚遠(上百倍),所以如何避免最差狀態比如何發揮最佳狀態更重要。
分區對齊
如果要對一塊SSD進行分區,然后再使用,就會遇到這個問題。當然,也可以不對它進行分區以避免這個問題。對于Linux來說,不分區直接使用就是
直接格式化 /dev/sdx 設備(比如:mkfs.xfs /dev/sdx),然后再 mount /dev/sdx /mnt/point
考慮到使用習慣、預留空間(見下文)的問題,以及安裝引導程序(如:grub)的要求,不做分區直接使用并不是個好主意。幸運的是,分區對齊問題是可以得到完美解決的。
害處
如果SSD上的分區分割點處于未對齊SSD block
size倍數的狀態,SSD效能就不能完全發揮,系統可能會有卡頓的感覺,另外,未對齊的分割點還會造成SSD在連續寫入小文件時,增加無謂的SSD額外
寫入/擦除動作從而大幅影響SSD的壽命,而這偏偏是SSD使用中最該避免的。
分區不對齊,對4KB隨機寫入的影響最大,實際測試表明,在其他因素相同的情況下,分區不對其導致的性能差距最大可達10倍。
CHS、LBA、block(塊)
在了解事情的來龍去脈之前,先得把傳統硬盤的幾個概念拿出來復習一下。
CHS(Cylinder-head-sector)是最早用于訪問硬盤的尋址方式。雖然CHS的值現在早已不再與實際的物理值相對應(只是個邏輯值),但是依然有許多磁盤管理程序(比如fdisk/cfdisk)使用CHS的方式來理解硬盤。
side/head
硬盤一般是由一片或幾片圓形薄膜疊加而成。每個圓形薄膜都有兩個"面"(Side),這兩個面都是用來存儲數據的。盤面由上而下從"0"開始編號,
依次稱為0面、1面、2面……由于每個面都專有一個讀寫磁頭,也常用0頭(head)、1頭……稱之。硬盤面數(或頭數),少的只有2面,多的可達數十
面。
按照CHS規范,head使用8bit編址,因此最多可以有256個磁頭(0-255)。但是由于某些古董程序只能最大支持到255個磁頭,出于兼容性考慮,絕大多數場合的默認值依然是255個磁頭。
track
讀寫硬盤時,磁頭不動,磁盤是旋轉的,則連續寫入的數據是排列在一個圓周上的。我們稱這樣的圓周為一個磁道(Track)。
磁頭不動,就是在一個磁道上讀寫;磁頭移動,就會在不同磁道上讀寫。
按照CHS尋址規范,由外向內從"0"開始順序編號。不過其編址時使用的位寬并不是一個定值(取決于不同的規范),我們姑且可以認為其足夠大。
cylinder
各面上磁道號相同的磁道合起來,稱為一個柱面(cylinder)。也就是距軸的距離相同的一組track所形成的圓筒。
按照CHS尋址規范,cylinder和track一樣,也由外向內從"0"開始順序編號。并且其編址位寬足夠大。
cylinder也是磁盤分區時的最小單位,分區是按磁道和柱面連續分布的(即每個分區,都是粗細連續的一組筒子)。
下面是一個fdisk的輸出,主意最后一行:
# fdisk /dev/sda Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-524, default 1):
Sector
一個track上可以容納"較多"的數據,而主機讀寫時往往并不需要一次讀寫那么多,于是,磁道又被按512或4096字節劃分成若干段,每段稱為一個扇區(Sector)。一個扇區的大小是固定的512或4096字節。
計算機對硬盤的讀寫,是以扇區為最小單位。即使只讀某一個字節,也必須一次把這個字節所在的扇區中的512或4096字節全部讀入內存。
按照CHS尋址規范,Sector的編號始終是從"1"開始的(不是"0")。由于使用6bit編址,所以其最大值是63,也就是說既不存在 sector 0 也不存在 sector 64 。目前所有機械式硬盤在邏輯CHS模式中都使用63這個最大值。
block
Block是文件系統的最小存取空間。一個 Block
最多僅能容納一個文件(即不存在多個文件同一個block的情況)。如果一個文件比block小,他也會占用一個block,因而block中空余的空間
會浪費掉。而一個大文件,可以占多個甚至數十個成百上千萬的block。
# df / (/dev/dsk/c0t3d0s0 ): 573548 blocks 226057 files /proc (/proc ): 0 blocks 3854 files /var (/dev/dsk/c0t3d0s1 ): 1897206 blocks 250028 files /var/run (swap ): 611424 blocks 26300 files /tmp (swap ): 611424 blocks 26300 files
sector 和block的差別
-
sector 是硬盤存取的最小單位,是512B或4096B
-
block 是文件系統的最小存取單位,可以隨意設定,但必須是sector的整數倍。如ext2 fs的block缺省是4k
應該根據自己系統應用的特點,合理規劃block size:若block太大,則存取小文件時,有空間浪費的問題;若block太小,則硬盤的
Block 數目會大增,而造成 inode 在指向 block 時候的一些搜尋時間的增加,又會造成大文件讀寫方面的效率較差。
磁盤容量
先看一個500G的硬盤在 fdisk -l 時顯示的信息:
# fdisk -l /dev/sda Disk /dev/sda: 500.1 GB, 500107862016 bytes 255 heads, 63 sectors/track, 60801 cylinders, total 976773168 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/sda1 63 8000369 4000153+ 83 Linux /dev/sda2 8000370 95891984 43945807+ 83 Linux /dev/sda3 95891985 427923404 166015710 83 Linux /dev/sda4 427923405 976768064 274422330 83 Linux
可以看出,磁盤總容量=磁頭數*每磁道扇區數*柱面數*扇區大小。當然,這里的磁頭數、扇區數、柱面數并不是物理真實值,而是邏輯值。甚至對于4KB扇區的硬盤,扇區大小也可能是邏輯值。
LBA尋址機制
上面說的CHS尋址方式其實在實踐中早就被丟進垃圾箱了。目前在實踐中真正使用的是48位LBA(Logical Block
Address)尋址方式。LBA是非常單純的一種尋址模式:從0開始編號來定位區塊(扇區),第一區塊LBA=0,第二區塊LBA=1,依此類推。以每
扇區512字節計算,容量上限可達128PB。LBA尋址模式完全屏蔽了硬盤的物理結構,而將其簡單的抽象成一維條帶,非常便于操作系統的理解。
原因分析
了解了上面的知識之后,現在知道了機械硬盤從很早前開始,扇區大小就被定義為512字節,而最新的"先進格式"機械盤終于把物理扇區提高到
4KB(4096字節)。機械式硬盤的最小操作單位是扇區,也就是說,無論讀取還是寫入1個字節、10個字節、500字節,實際的操作都是512字節。當
然,對于4KB扇區的機械式硬盤來說,所有讀寫操作都會被向上取整到4KB的整數倍。
但SSD的操作方式與此不同。SSD不像HDD那樣只有讀/寫兩種操作而且還是統一的,SSD有三種操作:讀/寫/擦除。閃存的讀寫單位是4KB或8KB大小的頁,而且閃存的擦除(又叫編程)操作是按照128或256頁大小的塊來操作的。
傳統上,LBA模式的HDD第一個分區的起始點從63邏輯扇區(63x512B=31.5KB)開始,對于扇區大小為512B的HDD來說,這當然
沒什么問題。但對于SSD和新式HDD來說,就會造成用戶的第一個數據的前4KB會存放在系統"邏輯扇區"的31.5KB~35.5KB間,這樣持續下去
會造成后面所有的數據都會卡在2個物理扇區(頁)容量之間,我們知道扇區(頁)為磁盤寫入的最小單位,如果卡在2個扇區(頁)之間,寫入的時候就需要進行
讀-改寫操作(對SSD來說讀-擦-寫),造成性能的下降。
分割點應該放在哪里呢?
簡單的說,應該放在SSD最大操作單位"塊",也就是block size整數倍的位置。
對于單通道的閃存設備,這很簡單,也很好理解。但事實上,幾乎所有的SSD都不是單通道的,這時候應該空出多少呢?
多通道的閃存設備也是把數據拆成一個一個的塊,然后分別對每個通道進行讀寫操作,這個塊的大小和所使用的閃存芯片的塊的大小是一樣的。如果多通道
SSD會把數據再進一步拆分然后才寫到各個通道的話,情況就會變得復雜了。不過目前的SSD主控似乎還沒有這么聰明,目前多通道寫入時最小的數據單位依然
是閃存塊的大小。因此,在目前的情況下,我們完全可以不考慮設備是幾通道的,直接把分區分割點設在block
size整數倍的位置即可。也許未來需要把分割點設置在"通道數*block-size"整數倍的位置?
FDISK
在給出最終解決方案之前,先來了解一下fdisk工具:
# fdisk -h Usage: fdisk [options] <disk> change partition table fdisk [options] -l <disk> list partition table(s) fdisk -s <partition> give partition size(s) in blocks Options: -b <size> sector size (512, 1024, 2048 or 4096) -c[=<mode>] compatible mode: 'dos' or 'nondos' (default) -h print this help text -u[=<unit>] display units: 'cylinders' or 'sectors' (default) -v print program version -C <number> specify the number of cylinders -H <number> specify the number of heads -S <number> specify the number of sectors per track
我們通常并不使用任何選項,但是為了強制分割點的位置對齊,就必須強制指定如下三個參數:
-
-b
-
指定扇區的大小,只能取 512/1024/2048/4096 之一。
注意,經過本人實測,使用大于512的其他值(假定是N),會導致fdisk只能使用到真實容量的512/N。所以最好不要使用該選項。 -
-H
-
指定磁頭數,只能取 1-256 之間的整數。
-
-S
-
指定每磁道扇區數,只能取 1-63 之間的整數。
這三個參數值的乘積就是一個邏輯柱面的總大小,也就是最小分割單位了。
解決方案
經過前面的講解,現在知道,只要把"塊"作為SSD的最小單位來劃分磁盤就能完美解決分區對齊的問題。
現在假定我們拿到一塊SSD的參數是這樣的:每個頁的大小是8KB、每256個頁組成一個塊,那么也就是說我們必須以
256*8KB=2097152B=2048KB=2MB為最小單位對其進行分區。也就是說,我們可以通過強制指定fdisk的命令行參數,使每個柱面
(cylinder)的大小為2MB即可達到目的(假定每扇區512字節):
fdisk -u=cylinders -H 128 -S 32 /dev/sdx
如果覺得每個柱面(cylinder)的大小為2MB還是不夠大,那么可以加大到4MB(假定每扇區512字節):
fdisk -u=cylinders -H 256 -S 32 /dev/sdx
此外,還需要注意一個細節,那就是第一個分區的起點不能從默認的第一個柱面開始,而是要從第2個柱面開始,否則第一個分區有可能依然不會對齊。如下圖所示:
Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4, default 1): Using default value 1 First cylinder (1-800, default 1): 2Last cylinder, +cylinders or +size{K,M,G} (2-800, default 800): 500
注意 First cylinder 那一行,那里的默認值是1,但是不能用它,要手動修改為2。
導致這個問題的原因,據Google說是fdisk會對從 cylinder 1 開始的扇區特殊對待,自作主張的向前平移分區起點。不過,既然新版本的fdisk已經修正了這個bug,我們就不必再去考古了。
對齊檢查
如何檢查分區是否確實已經對齊呢?方法是使用"fdisk -u=sectors -l /dev/sdx"查看。例如:
# fdisk -u=sectors -l /dev/sda Disk /dev/sda: 671 MB, 671088640 bytes 128 heads, 32 sectors/track, 320 cylinders, total 1310720 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x7bf5a16d Device Boot Start End Blocks Id System /dev/sda1 63 40959 20448+ 83 Linux /dev/sda2 40960 79871 19456 83 Linux /dev/sda3 81920 163839 40960 83 Linux
首先看 Sector size 的大小,有logical/physical兩個值,都是512字節。
sda1分區的Start=63,那么就表示sda1分區的起始扇區頭距離LBA0的距離是63*512B=31.5KB,顯然是未對齊的。
sda2分區的Start=40960,表示sda2分區的起始扇區頭距離LBA0的距離是40960*512B=20MB=5*2*2MB,顯然
既在2MB大小的塊邊緣對齊,也在4MB大小的塊邊緣對齊;再看sda2分區的End=79871,表示sda2分區的終止扇區尾距離LBA0的距離是
(79871+1)*512B=39MB,顯然只能在1MB大小的塊邊緣對齊,但是不能在2MB/4MB塊的邊緣對齊。
sda3分區的Start=81920,表示sda3分區的起始扇區頭距離LBA0的距離是81920*512B=40MB=5*4*2MB,顯然
既在2MB大小的塊邊緣對齊,也在4MB大小的塊邊緣對齊,甚至對于8MB大小的塊也是對齊的;再看sda3分區的End=163839,表示sda3分
區的終止扇區尾距離LBA0的距離是(163839+1)*512B=80MB=5*2*2*2*2MB,顯然可以在2MB/4MB/8MB/16MB塊
的邊緣對齊。
可見sda3是對齊最完美的分區,而sda1則是最糟糕的。
文件系統
現在SSD已經被完美的分區了,接下來就是創建文件系統了,那么哪個文件系統才是最適合SSD的呢?因為Linux系統有如此多的文件系
統:etx2/ext3/ext4/reiser3/reiser4/JFS/XFS/Btrfs/NILFS2……在HDD的時代,選擇合適的文件系統
就一直是個令人頭痛的問題。直到目前為止,不得不說,沒有任何一個文件系統和SSD是絕配。
未完待續。。。
原創文章,作者:追馬,如若轉載,請注明出處:http://www.www58058.com/2886