--- tags: flash storage --- # SSD for beginners :::info 本文主要摘錄並翻譯自 [Coding for SSDs](https://codecapsule.com/2014/02/12/coding-for-ssds-part-6-a-summary-what-every-programmer-should-know-about-solid-state-drives/) ::: ## Basic concepts ### Overview SSD 是一種基於 [flash memory](https://en.wikipedia.org/wiki/Flash_memory) 的儲存裝置,其組成完全由電子元件製成,而沒有像機械式硬碟那樣的機械部件(磁頭)。並且,SSD 與一般機械式硬碟的寫入資料方式也不相同。 :::info 本文以使用 nand flash 的 SSD 為主進行討論,文中的 "flash" 單字可以直接理解成 nand flash ::: 在 flash 中,儲存空間被劃分為許多相同尺寸的區塊(術語上稱為 block),而每個 block 又被切割成相同大小的區塊(術語上稱為 page)。每個 page 又分成容納 user data 的區域,以及存放管理所需要信息的區域,例如 [ECC](https://en.wikipedia.org/wiki/Error_correction_code) 或 bad block indicator。 對於 flash 的資料寫入(術語上稱為 program),該操作是以 page 為單位進行的,已經被寫過的 page 不能被直接重新寫入(overwrite),必須先經過擦除(術語上稱為 erase) 的動作才能再次寫入。然而,erase 操作是以 block 為單位,與 program 的操作單位不同,這造成了檔案系統在 SSD 與傳統硬碟的考量點差異。 對 flash 的寫入操作是會帶來裝置的磨損,導致無法使用的。其壽命會由所謂的 P/E cycle (i.e. Program/Erase) 決定,超過次數的 block 將無法正常地執行讀寫動作。 :::info 為了延續 SSD 的價值,當僅剩的 good block 數量已經不足以支持系統順利的運作時,可能切換為 write protect 模式。在此模式下,SSD 只讀不寫,以維持最低限度的 SSD 用途。 ::: 此外,對 flash 讀取也會導致 block 中的附近單元隨時間被錯誤的改動,導致資料被損壞的問題([read disturb](https://en.wikipedia.org/wiki/Flash_memory#Read_disturb))。為此,flash controller 通常會計算自上次 erase 以來對 block 的讀取總數,當數目超過目標限制時,受影響的 block 被複製到一個新的 block,然後把舊的 block erase 成 free page。 ![](https://i.imgur.com/qs4RU26.png =600x) 如上圖所展示的 SSD 架構與 host,host 對 SSD 的控制會透過對 SSD controller 發送命令(command) 來運作。主機和儲存裝置之間的數據傳輸通常是透過 [Serial ATA (SATA)](https://zh.wikipedia.org/wiki/SATA) 或者是 [PCI Express (PCIe)](https://zh.wikipedia.org/wiki/PCI_Express) 介面進行的。從圖中我們還可以看到,SSD 本身也帶有 embedded RAM memory,這讓 SSD 可以具有 caching 機制並且儲存 controller register,host 可以透過 mapping 的方式儲存到該 RAM。 :::info 本文專注在對於 firmware / filesystem 比較重要的知識上,而對硬體設計也想涉略者,可以在 [Coding for SSDs – Part 2: Architecture of an SSD and Benchmarking](https://codecapsule.com/2014/02/12/coding-for-ssds-part-2-architecture-of-an-ssd-and-benchmarking/) 原文上閱讀更多相關知識。 ::: ### SSD Operations 對於 SSD 的基礎操作 Read, write, erase: * read: 從 SSD 讀取資料必須以 page 為單位 * write("program"): 從 SSD 寫入資料也必須以 page 為單位,並且,只有 free page 是可以被 write 的,因此當檔案系統的邏輯上發生 overwrite 時,SSD 實際上是把 page 複製到內部 RAM buffer,更新相對應的部分後,再把新版本儲存在另一個 free page 裡,這個操作稱為 read-modify-write * erase: 要將被寫過的 page (稱為 stale page) 重製回 free page 需要透過 erase 操作,然而 erase 必須以 block (pages 的集合)為單位進行。從 user 的角度來看,訪問資料時就只是發出讀寫命令,而當需要回收 stale page 以騰出可用空間時,erase 會由 SSD controller 中的 garbage collection (以下簡稱為 GC)機制進行 ![](https://i.imgur.com/dpg8oOu.png =500x) 如圖簡化 SSD 的架構展示了上述的概念: 1. SSD 的初始狀態為在 block 1000 的 PPN 0, 1, 2 上有資料 2. 假設檔案系統對某一個檔案進行複寫時,實際上是對 block 1000 的 PPN 0 進行寫入操作,則硬體將新的內容更新在另一個 free page 上。從檔案系統的角度來看,之後對該檔案的後續讀操作會 reference 到 block 0 PPN 3 的 block 3. 此時,block 1000 的 PPN 0 上存放的資料實際上是無效(過期)的,藉由 GC 機制可以將其回收: 將特定 block 的有效資料搬動到其他 page 之後,將該 block 整個 erase ### Write amplification 理想上,可以對 flash 寫入的資料總量是整個 flash 的容量大小乘上其 P/E cycle,但是,撇開 P/E cycle 的理想值與實際裝置的情形不一定符合的情況。實際上,從 host 角度寫入的資料數量與 flash 內部運作時寫入的資料並不一定是一致的: * 寫入是要求 page aligned 的,因此任何不是在 page 大小的整數倍上進行的寫操作都將需要比預期達成的寫入更多的資料,這導致僅僅 1 bytes 需求的寫入實際涉及一個完整的 page 寫入 * 因為 SSD 的特性,覆寫資料的一小部分會導致 read-modify-write,過程中實際對 SSD 寫入的數量也超出要求的大小 * garbage collection 時的資料搬動 * 為了預防斷電,需要額外保存一份 L2P table 在 flash(詳見 [Flash Translation Layer](#Flash-Translation-Layer(FTL))) 這些額外的寫入導致了寫入放大([write amplification](https://en.wikipedia.org/wiki/Write_amplification)),除了影響 SSD 的效率也造成 SSD 的壽命縮短。 $$ WAF = \frac{\text{data written to flash}}{\text{data written by host}} $$ ### Wear leveling 我們曾經提到 flash 的壽命取決於 P/E cycle,每個 block 各自可以承受的 program 和 erase 達到一定上限之後,就將不再可以被使用。換句話說,如果有特定的 block 比起其他 block 在使用過程中更容易被讀寫,它將很快超過其 P/E cycle 的限制,SSD controller 會將其標記為不可用,整個 SSD 的容量就因此下降了! 因此,SSD controller 還需要考慮另一個目標: 實現 Wear leveling(磨損均衡)。在 block 之間盡可能均勻地分配 P/E cycle。使得理想情況下,所有 block 可以同時達到磨損上限。 為了實現最佳的 Wear leveling,SSD controller 在寫入時需要明智地選擇 block。但資料有分成寫入後就不太會改變的 cold data 與頻繁變動的 hot data 之分。如果 cold data 不會被更動,就將其放在原本的位置不動顯然是最恰當的。但為了使 cold data 所在的區域達到 wear leveling,就不得不讓 hot data 也可以寫到 cold data 所在的區域中。這導致了 write amplification 的問題。因此,對 block 的管理實際上就是在最大化 wear leveling 和最小化 write amplification 之間的 trade-off。 ### Endurance 除了 SSD 的效能與容量之外,壽命長短也是非常重要的一個考量。衡量 SSD 的壽命主要有兩個指標,一是 TBW(Tera Bytes Written) 代表在 SSD 的生命週期中在損壞前,總共可以寫入多少 TB。 $$ TBW = \frac{\text{NAND size(TB) * PE cycle}}{\text{WAF} \times \text{wear_level_factor}} $$ 而另一個指標是 DWPD(Drive Writes Per Day),代表用戶每天可以寫入多少次。 $$ DWPD = \frac{\text{TBW}}{\text{SSD size(TB)} \times \text{warranty data}} $$ 舉例來說,假設 SSD 的容量是 256GB,DWPD 是 1.5,代表用戶只要每天平均寫入的資料量不超過 256GB x 1.5 = 384GB,則 SSD 在保固期內不會損壞。 > * [DWPD (每日全碟寫入次數)](https://ind.adata.com/tw/technology/89) ### Reliability SSD 是否可以正確保存資料也是重要的考量點。Bit Error Rate(BER) 是指 NAND flash 可能發生Bit 位元翻轉而導致的錯誤,其中,RBER (Raw Bit Error Rate) 指沒有經過 ECC 糾錯時出現錯誤的幾率,舉凡 P/E cycle 的增加、retention(產品放置時間太久)、溫度增加都會導致 RBER 的上升。 不過,用戶可能更在意 ECC 無法處理的部分,UBER(Uncorrectable Bit Error Rate) 定義了發生不可糾正 ECC 錯誤的機率: $$ UBER = \frac{\text{number of data errors}}{\text{number of bits read}} $$ 為了解決儲存資料產生錯誤的問題,SSD 也會具有 ECC 機制來處理。在 SSD 中的 ECC 策略主要的選擇有 BCH(Bose, Ray-Chaudhuri, Hocquenghem) 和 LDPC(Low Density Parity Check Code) 兩種,後者因為具備更佳的錯誤更正能力而逐漸成為趨勢。可見 [糾錯精準更高效 LDPC 提升 Flash 可靠度](https://www.2cm.com.tw/2cm/zh-tw/tech/ADD090A6B93E44D5BFA4FBD10617C8DB)。 :::info 考量到 SSD 的錯誤機率與其生命週期是有相關性的,我們可以在 SSD 使用 adaptive ECC 策略,讓 SSD 隨使用越久而有更長的 parity,雖然會導致 over provisoning 減少但提供更高的糾錯能力 ::: SSD 中還有一些其他的糾錯機制。例如透過 read retry。因為儲存的本質上就是存儲 0 和 1,實現上就是用不同的電位表示 0 和 1。而隨著 SSD 使用的 PE Cycle 增加,電壓的 threshold 會偏移,因此正確讀取數據需要更高的電壓,而 read try 即通過嘗試偏離正常值的電壓找到偏移後的電壓 threshold,以試圖正確讀出數據。 > [手機變慢了?不只是系統垃圾在作怪,可能是Read Retry](https://kknews.cc/zh-tw/tech/5rnqzm6.html) 另一種會導致資料錯誤的原因來自意外地停電。SSD 也提供斷電的保護: * Super capacitor: 備份電源提供額外的運作時間以進行必要的保存 * [MRAM](https://en.wikipedia.org/wiki/Magnetoresistive_RAM) ## Flash Translation Layer(FTL) SSD 的一個使用上容易的點,來自其與 HDD 有相同的 host interface。但我們都知道 SSD 實際上的工作方式與 HDD 不同,overwrite 設置資料的搬動而不是直接覆蓋,直接把 host 端操作的位址直接對應到物理儲存位置是不適合的。 出於這個原因,需要一個額外的組件來隱藏 SSD 的內部結構,這個組件被稱為 flash translation layer(FTL),屬於 SSD controller 的一部分。FTL 機制在兩個主要目的上可以帶來效益:logical 與 physical 的映射和 GC。 ### Logical Address to Physical Address (L2P) FTL 的映射機制將 logical block address(LBA) 映射為物理 SSD 空間中的 physical block address(PBA)。這種映射採用 table 的形式,對於任何 LBA,這個 table 都給出了相應的 PBA。當一個寫請求被送達時,FTL 將到達的數據寫到一個處於 erased 狀態的 page,並更新 mapping 以指向最新的 physical page 的位置。原本的 logical address 對映的舊 page 具有的資料將變得過時並無法存取。 為了轉換的速度,table 通常是放置在 RAM 上的,不過若僅僅如此,SSD 斷電後 table 就會跟著消失。為了在重新啟動時可以找回這個 table,我們可以在關掉電源前把 table 同時寫入 flash 裡。但如果 SSD 發生意外的斷電怎麼辦呢? 也許我們可以激進在 table 變動時也更新到 flash,但是這額外的工作可能降低整個 SSD 的讀寫速度。Super capacitor 也許可以幫助到我們。總之,雖然本文不會嘗試深入這個問題,但管理 table 的方法顯然不是表面上的簡單。 關於 L2P 的轉換,一種最簡單的方法是使用 page 等級的映射將 LBA 映射到 PBA。這種策略提供了很大的靈活性,但主要缺點是因為 page 的顆粒度較小,要建立映射表就需要大量 RAM。改成使用 block 等級的映射可以稍微減少此問題。但是,在具有大量微量資料更新的工作情況下,更改 page 等級就已經足夠了,block 等級的映射反而會造成嚴重的 write amplification(映射關係的修改變成以 block 為單位)。 Block level 與 page level 間的選擇就意味著空間與效率間的權衡。這種時候就有人提出了我全都要的 hybrid 方法。例如 log-block mapping。簡而言之,這種做法是將原始資料以 block-level mapping 方式維護的 data block,而新的資料則寫入以 page-level mapping 方式維護的特定 log block。也就是說,只有 log block 部份需要 page-level table。小資料的寫入先進到 log block,等 log 存到一定量再合併成 block 更新。 ![](https://i.imgur.com/WNP3WTn.png =600x) 如上圖展示了一個簡化版的 log-block mapping 示例。假設我們即將進行四次 page 大小資料的寫入,寫入的 logical page address 5, 9 都對應到 LBN 1,後者根據 log-block page mapping table 關聯到一個空的 physical block 1000。 一開始 log-block page mapping table 1、 block 1000 是空的,隨著寫入新資料 / 複寫到 block 1000 的過程會以 page-level 的 mapping 來新增/更新其對應位置。直到 log-block 1000 被完全填滿時,它與關聯到同一 logical block 的數據進行 merge,根據 data block mapping table 是 block 3000。合併產生的資料被寫入另一個 free 塊,假設是 9000。完成後,block 1000 和 3000 都可以被 erase 並成為 free block。 需要讀取 page 時該怎麼辦呢? 如果讀取的是一個最近更新的 page,並且 block 上的 merge 尚未進行,那麼該 page 將位於 log block 中。 否則,page 會存在一個 data block 裡。如圖所示,在進行讀取時需要同時檢查 log-block page mapping table 和 data block mapping table。 這種機制的 FTL 允許了一種稱為 switch-merge, swap-merge 的優化機制。如果一個 LBA 中的所有 page offset 都有被寫入,這意味著舊的 block 現在都屬於 garbage 了。因此只需要更新 data block mapping table 中的 metadata 為當前的 log block 即可。 ### Garbage collection 如前所述,SSD 中的 page 不能被覆蓋。如果 page 中的資料需要被更新,則新版本會寫入其他 free page,而舊資料的 page 將被標記為過期(invalid)。當 block 包含舊 page 時,需要先 erase 它們,然後才能寫入。 但是 erase 操作的 latency 是很大的,如果要等到沒有 free page 再進行回收,使用者將會抱怨他們的 SSD 運行的特別慢。因此,SSD controller 會進行 background GC,利用 idle time 定期的回收舊 page,以確保未來的 foreground 有足夠的 page 可用。其他也有一些平行的 GC 機制,可以與來自 host 的操作在同時間點下執行。 FTL 在 GC 扮演了甚麼角色呢? 關鍵在於標註 page 為 invalid 使得 GC 可以正確運作。一種直接的作法是維護 bitmap 來主動追蹤 page 的 valid 與否。雖然 bitmap 的查詢相對有效率(透過 bitwise operation 足矣),不過 bitmap 需要占用的大量空間;因此另一種做法是透過 FTL,對於每個回收的 candidate page,我們可以將所有 LBA 進行 logical to physical 的轉換,如果轉換後的所有地址都與 candidata page 不相符,我們知道這個 page 屬於 invalid,允許被回收。這種方式雖然效率相對 bitmap 是比較差的,但是可以避免額外空間的消耗。 hot data 與 cold data 的存放方式是影響 GC 的因素。如果 page 中包含部分 cold data 和部分 hot data,則 cold data 會必須在 GC 時與 hot data 一起被搬動以進行 wear leveling,但這進而增加 write amplification。通過將 cold data 與 hot data 分開可以避免這個狀況,不過缺點是包含 cold data 的 page 較少被 erase,反而增加了磨損不均衡的現象。因此必須定期交換存儲 cold 和 hot data 的 block 以確保 wear leveling。 由於數據的 cold or hot 是在 host 層的角度才能看見的,FTL 無法知道單個 page 中包含了多少 hot 或 cold data。因此在 host 端可以主動的盡可能將 hot data 與 cold data 分為單獨的 page,降低 GC 的工作量以提高 SSD 的性能。 此外,SSD 提供的 [TRIM command](#TRIM) 和 [over-provisioning](#Over-provisioning) 可以有效的協助 GC 的效率,細節我們會在後面的章節中進行討論。 ## Advanced knowledge of SSD ### TRIM 大多數的檔案系統會以在作業系統層標記資料塊為「未使用」來處理刪除操作,而儲存裝置則不知道哪些空間是存在真正存在的資料的,意即檔案的刪除操作不涉及儲存裝置上的操作。然而,對於 SSD 而言,儘管作業系統將檔案刪除,並騰出了儲存空間。但在儲存媒介上,該刪除檔案所在的磁區只有在下一次寫入時,舊資料才會有機會被回收。甚至,因為 SSD 不知道這些資料是 invalid,因此在進行 GC 是會將其繼續的複製搬動,造成了額外的 wear、增加了 write amplification,進行不必要的工作而影響了 SSD 的執行效率。 從儲存媒介的角度看,「刪除」操作更接近於「重寫」(overwrite),而對於機械磁碟來說,寫入空與非空磁區並沒有區別,但因為 SSD 的一些特性,與寫入空 page 相比,overwrite 會有顯著的開銷,直接沿用管理傳統硬碟的檔案系統於 SSD 上是不夠合適的。 [TRIM](https://en.wikipedia.org/wiki/Trim_(computing))([ATA](https://en.wikipedia.org/wiki/ATA_Packet_Interface) 的名稱,或者在 [SCSI](https://en.wikipedia.org/wiki/SCSI_command) 裡稱為 UNMAP,在 [NVMe](https://en.wikipedia.org/wiki/NVM_Express) 裡則稱為 DEALLOCATE ) 提供了解決的方案。os 可以在檔案系統進行刪除邏輯的時候,同時發送 TRIM 來通知 SSD controller 該 page 不再使用。有了這些信息,GC 就知道它不需要四處移動這些 page,並且可以在需要時 erase 之。 需注意 TRIM 需要在 SSD controller、os 和 filesystem 皆支持時才有效,可以在 [Wikipedia](https://en.wikipedia.org/wiki/Trim_(computing)#Implementation) 找到支援的情形。 ### Over-provisioning [Over-provisioning](https://en.wikipedia.org/wiki/Write_amplification#Over-provisioning) 是 SSD 的物理容量與 OS 呈現給 user 的可用的邏輯容量之間的差異之比例。 ![](https://i.imgur.com/o1WCAEZ.png) 簡而言之,就是讓 SSD 具有比 LBA 更多的 PBA。在對 SSD 進行 GC、wear leveling、bad block mapping 等操作時,over-provisioning 產生的額外空間有助於降低 write amplification 的問題,並增加產品的壽命。 > [How over-provisioning improves NAND-based ATP SSDs’ endurance and performance](https://www.atpinc.com/blog/over-provisioning-ssd-benefits-endurance-and-performance) ### Secure Erase 在一般的 SSD 機制下,被刪除的資料只是將其標註成 invalid(無論是透過 bitmap 或是更動 L2P table),並在 GC 啟動時才去 erase 之。如果使用者對資料的安全有疑慮,需要立即的 erase,則可以使用 secure Erase 指令要求 controller 立即進行刪除。但注意到 secure erase 只是刪除邏輯上的對應,從 host 的角度不能再取得資料,但在物理的上的數據仍會存在。後者可以透過更激進的 sanitize 清除掉。 > [什么是 SSD Sanitize 数据擦除技术?](https://xie.infoq.cn/article/b6c188ed49cac7965ba963f18) :::info [Coding for SSDs – Part 4: Advanced Functionalities and Internal Parallelism](https://codecapsule.com/2014/02/12/coding-for-ssds-part-4-advanced-functionalities-and-internal-parallelism/) 上還提了一些 SATA 的特殊指令以及斷電保護的機制,不過因為沒有深入的討論篇幅,本文也就不另外擷取 ::: ## Parallelism in SSDs 由於物理上的限制,flash I/O bus 能夠提供的 bandwidth 是有極限的。 SSD 製造商能提高性能的唯一方法是將其設計為可以平行或 interleaved (類似於 CPU pipeline 的想法)。而 host 通過結合 SSD 內部所有級別的內部平行性,可以跨 chips 同時存取多個 block,這些可以同時存取的 block 作為一個稱為 clustered block 的單位,提供最佳的 SSD 存取效率。 ![](https://i.imgur.com/vrYyH5w.png) SSD 的層次結構由 channel, package, chip, plane, block, 到 page 分級,如上圖所示 * chip 與 die 區別的重要特性是 enable 和 ready/busy signal bus * 一個 chip 具有 enable 和 ready/busy * die 是 chip 的元件,只有内部的 ready/busy * 多個 chip 被放一起作為 package,他們共同使用 8/16 bits 的 data bus,但是各自有獨立的 enable 與 ready/busy signal bus。 而根據平行所在的層級可以區分成 * Channel-level parallelism: controller 需要通過 channel 與 package 進行通信,每個 channel 由多個 package 共享,而這些 channel 可以被同時 access * Package-level parallelism: 同個 channel 上的 package 可以被同時存取 * Chip-level parallelism: 同個 package 裡上的 die/chip 可以被同時存取 * Plane-level parallelism: 同個 chip 裡面有兩個以上的 plane, 一個 command 可同時對 chip 裡的各 plane 進行 ![](https://i.imgur.com/O8z3b6w.png =600x) 結合 SSD 所有等級的平行性下,多個 block 可做為 clustered block 被同時存取,這個概念跟 HDD RAID 的 striping 概念相近。因為有 FTL 層,一次訪問的 logical block address 可以分散到在不同 package 中的不同 SSD chip 上。如上圖,我們把對一個 logical block 的操作映射到這個 clustered block 中,則可以得到平行的效益。這也意味著當我們將 I/O 對齊 clustered block 且大小為其之整數倍數時,將可充分利用 SSD 內部各層級的平行運作機制。 > * [SSD 编程学习笔记(一)](http://cighao.com/2016/03/29/the-note-of-SSD-studying-1/) > * [SSD 并行的性能影响](http://blog.foool.net/2012/04/ssd-%E5%B9%B6%E8%A1%8C%E7%9A%84%E6%80%A7%E8%83%BD%E5%BD%B1%E5%93%8D/) > * [论文阅读:SSD内部多级并行性的探索和利用(TOC 2013)](http://cighao.com/2016/07/20/paper-reading-02-the-multilevel-parallelism-inside-SSDs/) ## Performance ### 測量指標 SSD 的效能分析主要可以看兩個指標: * Throughput <- sequencial * 每秒的資料傳輸大小 (MB/s) * 取決於系統的最大 bandwidth(host, system, flash 三大關口) * IOPS <- random * 每秒可處理的 I/O command * 取決於系統對 I/O 的處理能力 * throughput = IOPS * Cmd access size 測試的方式可以有以下幾種: * Access pattern(sequnce or random) * Command package size(4kb, 8kb,...) * Command queue depth(QD1, QD4, QD32,...) * Access range: 操作儲存空間的範圍(gc 的影響) * Host thread number 根據工作狀態,效能的測試也可以分成 burst 和 sustain。前者是基於空的 SSD 下進行測試,可以測試 SSD 極限的讀寫速度;後者則測試 SSD 的運作更接近真實的應用狀態時,即已經儲存某些資料,對 GC 的設計、over provisioning、flash bandwidth 進行更符合實際的評估。 在企業級的產品中可能會有其他的考量,需要進行 Quality of Service(Qos) 的測試。這個測試可以分為兩個面相: * Macro QoS: 測試 I/O 的穩定性,即 IOPS 在每個時間單位的變化,變化越小表示提供 service 可以更為穩定 * Micro Qos: 測試 I/O command 的 responce latentcy ### Write Performance ![](https://i.imgur.com/5IfvPCL.png =600x) > [Parameter-Aware I/O Management for Solid State Disks (SSDs), Kim et al., 2012](http://csl.skku.edu/papers/CS-TR-2010-329.pdf) ![](https://i.imgur.com/2v0EFfG.png) > [Comparison of the effects of a sequential write workload versus a random write workload over three SSDs — Reproduced from Min et al., 2012](https://www.usenix.org/legacy/event/fast12/tech/full_papers/Min.pdf) 對於 random writes 和 sequential writes,如果寫入的大小很小,具體來說是小於 clustered block,則 random 比 sequential 慢。但是,如果 random 是 clustered block 大小的整數倍且位址與 clustered block 對齊,則他將與 sequential 的效能接近的,可以參考上面的圖。 原因為: 因為 SSD 中的內部平行性允許使用一次寫入 clusted block。 因此無論是何種 pattern 的寫入,寫入都將在內部以相同的方式在多個 channels 和 chips 上平行進行。 然而若寫入的大小較小,因為單位較小,random pattern 可能跨越的 page 就更多,導致了相對 sequential 需要更多對 RAM 上的 L2P mapping table 進行修改,加上 mapping table 也可能需要在 flash 上的備份,random 相對 sequential 更多額外的工作導致了效能的降低。也因為 random 跨越的 page 更多,將導致對進行更多的 copy-erase-write。且相較於 sequntial 只會讓特定幾個 block 包含 invalid page,小量的 random write 會在不同的 block 中隨機產生 invalid page。這種現像被稱為 internal fragmentation,會導致 GC 的清理效率下降。 最後是關於 SSD 平行性的利用部分,實驗表明用一個 thread 寫入一個大 buffer 與用多個 concurrent thread 寫入許多小的 buffer 之 throughput 一樣。而實際上,大量寫入可確保使用 SSD 的所有內部平行,得到更佳的 response time。因此,如果可能的話,盡量一次進行大量的寫入。 ### Read performance 寫入時,FTL 動態的將 LBA 動態映射到 PBA,並跨 channels 的盡量善用 SSD 內部的平行寫入。 這種方法有時被稱為 write-order-based mapping。則如果 read 時的 pattern 與最初寫入不匹配,是以完全隨機的方式讀取資料的話,則無法保證 read 分佈在不同的 channel 上。 ![](https://i.imgur.com/YN0bwhb.png =500x) 如上圖所展示的範例(注意到一般的 SSD 中一個 chip 裡不會只存在單個 plane,這裡只是為了簡化解說)。我們寫入四筆連續的 LBA 資料 [A, B, C, D],剛好也是 clustered block 的大小。因此硬體可以善用平行機制分開寫到四個 plane 去。現在假設我們有兩個讀取 [A, B, E, F] 與 [A, B, G, H] 的時候,前者因為資料在同個 plane 裡重複,無法善用空閒的 channel 1,後者則可利用平行機制。 類似於 write,嘗試使用多個執行緒讀取資料不一定會提高性能,最差情況是 read pattern 最終存取同一個 channel。甚至有研究指出多執行緒讀取會削弱 SSD 的 readahead (prefetching buffer) 功能。 另外,交錯進行讀寫對效能會產生負面的影響,因為兩個操作會互相競爭資源、妨礙例如 readahead buffer 的運作,因此讀寫操作應該盡量被分開。 ## Reference > * [SSD筆記 - 第三篇 FTL, GC](https://www.owlfox.org/blog/2019-11-27-coding-for-SSD-part-3/) > * [Coding for SSDs](https://codecapsule.com/2014/02/12/coding-for-ssds-part-6-a-summary-what-every-programmer-should-know-about-solid-state-drives/)