SSD (固態硬盤)

此頁由 郭枫 於 2014年2月23日 (星期日) 02:02 的最後更改。 在Tom Lifunicorn和Linux Wiki用戶Chenxing的工作基礎上。

出自Linux Wiki

提示:此文已超过 2 年(1063 天)未更新,如发现内容过时或有误,欢迎改进:)
Note.gif
謹慎轉載:
雖然您有在保留本文鏈接的條件下轉載本文的權利,但考慮到轉載不當可能破壞文檔排版,且難以實時展現文檔的最新版本,請在轉載前慎重考慮。如果您發現文本內容有錯誤或不足,可以登錄後直接更正或改進;如果不確認應如何改進,也可以使用 TODO 模板留下標記。

SSD(Solid State Drive,固態硬盤)以其讀寫速度快、尋址快、無機械移動部件、無噪聲等突出優點日益受到人們的青睞。由於其工作原理與傳統的磁盤完全不同,故在操作系統和應用程序層面都有對其做專門優化的空間。

值得一提的是,SSD硬盤無需任何特殊配置就可很好地應用在桌面環境上。本文介紹的配置可以改善SSD的性能和使用時間,但未必十分必須。

目錄

原理分析

SSD硬盤之所以需要特別優化系統配置,主要是由其特性決定的:

寫入方式
向SSD硬盤寫入數據時,不能像寫入普通硬盤那樣直接覆蓋,而是要先擦除、再寫入。不幸的是,由於設計的原因,雖然寫入操作可以以(page,常為 4KB)為單位,擦除操作的最小單位一般是(block,常為 512KB)。[1]如果想保留塊中的其它數據,需要在擦除前要先讀出該塊的數據到SSD緩存中(這也是SSD緩存一般較傳統磁盤大很多的原因之一),並在修改後寫回。所以每一次寫操作實際寫到硬盤上的數據很可能原來計劃比要寫的數據多,這就是所謂的 Write amplification 效應。這是SSD的讀取比寫入快得多的原因之一。
存儲單元損耗 (Wearing)
SSD的每一個存儲單元被擦除、寫入的次數是有限的。市面上常見的使用 MLC (Multi-Level Cell) 技術的SSD,單個存儲單元只能被擦除、重寫幾千次,而採用相對昂貴的 SLC (Single-Level Cell) 的SSD也有幾萬到幾十萬次的擦除壽命[2]。這是很多人對 SSD 硬盤不放心的因素之一,但實際上得益於耗損平均技術,該問題對普通用戶的影響並不顯著。
耗損平均技術 (Wear Leveling)
雖然每個存儲單元的壽命有限,但每個物理存儲單元對應的邏輯地址沒必要是一成不變的。通過將要寫入的數據動態地映射到不同的物理存儲單元,SSD的壽命可以得到明顯的提升[3]。如一個 64GB 的 SSD 設備,如果每個單元可被擦除、重寫3000次,而某桌面用戶每天寫入 10GB 的數據,該設備出現有存儲單元報廢需要約 64 * 3000 / 10 / 365 = 52年 。 由於一般來講桌面應用的寫入並沒有這麼多,所以因為擦除、寫入次數過多而導致SSD丟失數據的顧慮是沒有什麼必要的。一些評測數據[4]和分析文章[5]都支持了這一點。

針對以上特性,在軟件方面優化SSD的性能應主要集中在以下幾個方面:

  • 提高物理寫入的效率,減緩Write amplification
  • 充分利用SSD隨機訪問快的特性。
  • 減少不必要的硬盤寫操作。

與此相關的,涉及到如下兩個術語:

分區對齊 (Partition Alignment)
由於SSD向一個塊寫入數據前要先擦除整個塊,如果要寫入的一個邏輯塊分布在兩個物理塊中,那麼涉及到的兩個物理塊都要被擦除重寫。而如果將分區表和文件系統向物理塊對齊,就可以減少這種情況,延長硬盤的壽命。一般SSD的塊大小都能整除 512KiB [6],所以將分區的啟始邏輯位置設為 512KiB 或 1MiB 的整數倍通常是比較合理的。
TRIM
TRIM 本身是一個 SATA 指令。在刪除文件時,文件系統一般只做必要的標記而不真正抹去存儲介質上的數據。對於普通磁盤,這就足夠了,被標記的部分以後在需要時會被覆蓋。而對於 SSD 硬盤,告知硬盤有些塊不再被需要是很有意義的,硬盤可以據此優化其垃圾回收過程,加快以後寫入數據的速度。[1]

Linux環境配置

由於生產環境的需求通常各不相同,配置難以一概而論,這裡主要討論使用SSD的桌面Linux環境配置。

分區對齊

使用多數現代分區工具分區的硬盤,一般是已經對齊的。如在較新的GParted[7],新建分區的默認對齊方式就是 MiB(有些版本的GParted翻譯作“排序”)。

檢驗是否分區已正確對齊,可以通過 fdisk -l 命令(僅適用於使用MBR格式分區表)或 GParted 獲取分區的首扇區,由於邏輯扇區的大小一般是 512 字節,如果首扇區的扇區號是 1024 的倍數,則分區已向 512KiB 對齊,如果首扇區號是 2048 的倍數,則分區已向 1MiB 對齊。如:

$ sudo fdisk -l
Disk /dev/sdb: 96.0 GB, 96029466624 bytes
255 heads, 63 sectors/track, 11674 cylinders, total 187557552 sectors
Units = 扇区 of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00018744

   设备 Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048    62629887    31313920   83  Linux
/dev/sdb2        62629888   103606271    20488192   83  Linux
/dev/sdb3       103606272   144742399    20568064   83  Linux
/dev/sdb4       144742400   167077887    11167744   83  Linux

上例中,加粗部分均為 2048 的倍數,說明分區已對齊。如果發現分區不幸未對齊,則可能需要刪除分區重新來過了。

如果使用較新的GPT格式的分區表,則需要用gdisk查看。

掛載選項

Hint.gif
提示:
修改掛載選項的具體方法可參見fstab

開發中的btrfs正在試圖對 SSD 硬盤做專門的優化,用戶可以通過-o ssd掛載選項啟用[8]

另一個在很多教程中出現的選項是-o discard[6][9][10],該選項可用於 ext4btrfs 文件系統,作用是在刪除文件時實時發出 TRIM 指令,以期加快以後寫數據的速度。值得注意的是,該指令的效果是受到嚴重懷疑的[11]。2011年中旬的數據[12]表明, discard 選項非但沒有提升 SSD 的效率,反而使其變慢了。Btrfs的-o ssd選項也不會啟用discard[8]。 相比之下,定時發送 TRIM 指令可能是更好的選擇(見後文)。

noatime(或relatime), nodiratime是另外兩個可以考慮的掛載選項,它們防止在讀文件時更改文件的“最近訪問”時間戳,減少寫入硬盤的次數。[6][9]數據顯示,採用noatime選項後,在編譯Linux內核的過程中,硬盤寫入量比沒使用時少了約 13% 。[13] 請依照數據自行權衡利弊。值得注意的是,noatime可能會導致某些依賴時間戳的程序產生問題,因此現在通常relatime代替。

I/O 調度方案

默認的I/O調度一般針對磁盤尋址慢的特性做了專門優化,但對於SSD而言,由於訪問磁盤不同邏輯扇區的時間幾乎是一樣的,這個優化就沒有什麼作用了,反而耗費了CPU時間。[6][14]具體到 Linux 系統中,就是用 Noop 調度器 (直接把所有 I/O 請求送到一個隊列中)代替內核默認的 CFQ 調度器。

查看某設備當前使用的調度器的方法是:

$ cat /sys/block/sdX/queue/scheduler
noop deadline [cfq]

而下面的命令可以設置sdX的調度器為noop

echo noop > /sys/block/sdX/queue/scheduler

如想讓此成為默認設置,則需要將上面的命令加到自動啟動程序的列表中。

定時 TRIM

雖然實時TRIM選項-o discard效果並不好,但定期對已刪除的文件做TRIM還是有意義的[12],如:

# 告知硬盘分区"/"中的哪些块已不再被使用
fstrim -v /

推薦使用crontab定時執行該命令。

其它減少SSD寫入的方案

減少寫入固然可以延長SSD的壽命,但依前述分析,SSD 可寫入次數對於桌面用戶而言一般是足夠的。所以,在考慮採用減少 SSD 寫入方案時,要慎重分析其潛在的後果,再做決定。

在tmpfs里編譯

有些需要編譯安裝的軟件,在/tmp(通常掛載在內存上)中編譯通常是個不錯的選擇。

掛載需要頻繁寫入的分區到普通磁盤

有人建議將/var、交換分區等掛載到普通磁盤以減少對 SSD 的寫入,但這些操作也會同時導致系統性能的下降。對於桌面用戶而言,SSD上的/var一般會大幅包管理工具的性能,而SSD上的交換分區會讓系統休眠、喚醒的速度大大加快。

取消文件系統日誌

日誌文件系統是現代的文件系統的重要特徵,在內核崩潰或突然停電等突發事件發生後,有日誌的文件系統恢復起來要快得多。取消文件系統日誌固然會減少硬盤寫入,但也使文件系統的可靠性下降。有實驗結果顯示[13],關閉了日誌的文件系統在編譯內核的過程中硬盤寫入比未關閉日誌的大約少 3% - 6%,在刪除文件時少約 40% - 50% (刪除文件的寫入操作相對而言基數很小)。

所以對於有些教程提議的取消SSD的文件系統日誌以減少寫入以加快速度[10]的方案,一定要在謹慎分析後決定是否採用。

將瀏覽器緩存移入內存

由於大量小文件頻繁讀寫會損害SSD硬盤壽命,因此當tmpfs在當前的linux桌面上變得簡單易用時,將這些需要頻繁讀寫的文件掛載到一個tmpfs上進行日常操作,既加快了I/O速度,又可以大大降低硬盤讀寫次數,因此tmpfs成為了固態硬盤的絕佳助手。所謂tmpfs就是被掛載到當前根文件系統下的一段內存空間,它具有特定的訪問路徑和大小,可以讀寫,在系統斷電後會自動清空。tmpfs在win下有個不錯的中文翻譯,叫做“內存盤”(ramdisk)。

在一個普通用戶的linux桌面上,有一類應用軟件幾乎每天都要工作很長時間、並且有頻繁讀寫大量小文件的習慣,這種軟件被稱為瀏覽器。任何一種瀏覽器(例如Firefox、Chrome或Opera)都保留了一種工作特性,它會在硬盤的某個路徑下建立一份“檔案”(profile),然後在運行過程中頻繁而不間斷的讀寫檔案中的文件,這樣的文件大多與瀏覽器訪問過的網頁有關,這些文件被稱為瀏覽器緩存。在SSD上運行的瀏覽器,可能會因為大量讀寫緩存出現卡頓現象,並且可能影響SSD壽命。因此,如果能夠將瀏覽器的“檔案”移入一個tmpfs,讓瀏覽器在內存中讀寫檔案文件和緩存,就可以大大減輕SSD的負擔。

原則上,將瀏覽器的profile移入tmpfs是一件很簡單的任務,只需要先建立一個tmpfs分區,然後將瀏覽器的profile拷貝到tmpfs分區即可。然而tmpfs中的文件只駐留在內存中,系統斷電後這些文件就會被清空。很顯然,如果要保留對瀏覽器profile所做的修改,就必須適時對這些文件進行備份。掛載一個tmpfs、讓profile在tmpfs中工作、適時備份profile,這三個步驟就可以完美實現上面的計劃。而這三個步驟在一個很有名的腳本中已經完成了,這個腳本叫做profile-sync-daemon(psd)。

psd是一段讓多種瀏覽器的profile自動工作在tmpfs中並且定期備份的bash腳本。psd的配置非常簡單,它需要一個運行腳本(profile-sync-daemon),一個啟動服務文件(psd)和一個服務配置文件(psd.conf)。此外,psd在archlinux和gentoo中被擴充我為完整的軟件包,並且也存在debian和其衍生髮行版的deb包。psd支持firefox、chrome和opera等主流的瀏覽器,安裝啟動後自動在後台運行,每隔一小時對profile進行備份,daemon運行方式可以保證在關機或重啟電腦之前完成備份(daemon腳本的優點之一)。事實上psd並非只適合固態硬盤,由於可以加快瀏覽器運行速度,psd也運行於很多非SSD的linux桌面。

Note.gif
TODO:
普通桌面環境每天瀏覽器寫入的緩存大概幾何?是否值得將其移入內存?
Note.gif
TODO:
參考文獻,命令行示例

狀態檢查

如果對自己的SSD使用方式不放心,可以使用gsmartcontrol等工具,通過S.M.A.R.T.查看硬盤的狀況。一般ID 5 對應的 Retired Block Count (或作 Reallocated Sector Count)[15] 反映了SSD已損壞的存儲介質的情況。 Intel的SSD還提供233 Media_Wearout_Indicator,用一個整數來直觀反映SSD的老化狀況;以及225 Host_Writes_32MiB,反映已經向盤中寫入了多少數據。 [16]

 # smartctl -data -A /dev/sda
 smartctl 6.0 2012-10-10 r3643 [x86_64-linux-3.9.0-e-nvidia] (local build)
 Copyright (C) 2002-12, Bruce Allen, Christian Franke, www.smartmontools.org
 
 === START OF READ SMART DATA SECTION ===
 SMART Attributes Data Structure revision number: 5
 Vendor Specific SMART Attributes with Thresholds:
 ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
   3 Spin_Up_Time            0x0020   100   100   000    Old_age   Offline      -       0
   4 Start_Stop_Count        0x0030   100   100   000    Old_age   Offline      -       0
   5 Reallocated_Sector_Ct   0x0032   100   100   000    Old_age   Always       -       0
   9 Power_On_Hours          0x0032   100   100   000    Old_age   Always       -       4109
  12 Power_Cycle_Count       0x0032   100   100   000    Old_age   Always       -       422
 170 Reserve_Block_Count     0x0033   100   100   010    Pre-fail  Always       -       0
 171 Program_Fail_Count      0x0032   100   100   000    Old_age   Always       -       0
 172 Erase_Fail_Count        0x0032   100   100   000    Old_age   Always       -       0
 183 Runtime_Bad_Block       0x0030   100   100   000    Old_age   Offline      -       21
 184 End-to-End_Error        0x0032   100   100   090    Old_age   Always       -       0
 187 Reported_Uncorrect      0x0032   100   100   000    Old_age   Always       -       0
 192 Unsafe_Shutdown_Count   0x0032   100   100   000    Old_age   Always       -       216
 199 UDMA_CRC_Error_Count    0x0030   100   100   000    Old_age   Offline      -       0
 225 Host_Writes_32MiB       0x0032   100   100   000    Old_age   Always       -       203817
 226 Workld_Media_Wear_Indic 0x0032   100   100   000    Old_age   Always       -       1424
 227 Workld_Host_Reads_Perc  0x0032   100   100   000    Old_age   Always       -       60
 228 Workload_Minutes        0x0032   100   100   000    Old_age   Always       -       246549
 232 Available_Reservd_Space 0x0033   100   100   010    Pre-fail  Always       -       0
 233 Media_Wearout_Indicator 0x0032   099   099   000    Old_age   Always       -       0
 241 Host_Writes_32MiB       0x0032   100   100   000    Old_age   Always       -       203817
 242 Host_Reads_32MiB        0x0032   100   100   000    Old_age   Always       -       314998

參考資料

  1. 1.0 1.1 Wikipedia: TRIM
  2. Wikipedia: Write Amplification
  3. Wikipedia: Wear leveling
  4. SSD Write Endurance 25nm Vs 34nm
  5. SSD Myths and Legends - "write endurance"
  6. 6.0 6.1 6.2 6.3 ArchWiki: Solid State Drives
  7. GParted Manual: Specifying Partition Alignment
  8. 8.0 8.1 btrfs Wiki: FAQ
  9. 9.0 9.1 How to maximise SSD performance with Linux
  10. 10.0 10.1 開源中國社區:Linux 系統下使用 ssd 固態硬盤
  11. OpenSUSE Forum: SSD detection when creating first time fstab ?
  12. 12.0 12.1 OpenSUSE: SDB:SSD discard (trim) support
  13. 13.0 13.1 SSD’s, Journaling, and noatime/relatime
  14. Linux on Solid State Drives
  15. http://media.kingston.com/support/downloads/MKP_306_SMART_attribute.pdf
  16. ServerFault: How to determine number of write cycles or expected life for SSD under Linux?

本文对您有帮助?分享给更多朋友!

反馈与讨论

发现文档不全面、有错误却没时间编辑文档?想分享自己的经验或见解?欢迎在此留言、讨论。
简体繁体转换