為什么固態(tài)硬盤需要掉電保護?
作為企業(yè)級標準NVMe塊設備接口的固態(tài)硬盤固件,需要保證在存儲系統(tǒng)遇到異常掉電的情況下,或對盤進行熱插拔操作的情況下,保證盤上數(shù)據(jù)的可用性,正確性和一致性。
如果IDC機房忽然斷電,或者運維人員誤操作下了正在存儲數(shù)據(jù)的固態(tài)硬盤,發(fā)生數(shù)據(jù)丟失,可能會影響上層業(yè)務的運行,甚至導致客戶數(shù)據(jù)的丟失。后果可能會非常嚴重。
通常消費級的固態(tài)硬盤不需要添加掉電保護的功能,因為在消費級的PC上,通常不會存有特別關鍵的數(shù)據(jù),異常掉電帶來的數(shù)據(jù)丟失后果通常不大,只要固件功能能夠保證盤重新上電保證可用性即可。所以在成本的考量下,沒有必要在筆記本電腦的硬盤上增加掉電保護功能。
固態(tài)硬盤掉電保護的特性?
可用性:
在存儲系統(tǒng)異常斷電之后,重新給服務器上電,固態(tài)硬盤在回復主機端CSTS.RDY信息后,所有功能可用。
正確性:
保存在盤上的數(shù)據(jù),保證其數(shù)據(jù)不會因為異常掉電而被改變,成為錯誤數(shù)據(jù)。
一致性:
對于已經(jīng)回復host Completion Queue Entry(CQE)的寫命令數(shù)據(jù),固件應保證其信息的正確性。對于已發(fā)送未回復CQE的數(shù)據(jù),盤可以是老數(shù)據(jù),新數(shù)據(jù),或者新老混合數(shù)據(jù)的狀態(tài),其混合粒度與NVMe設計有關,在其粒度內(nèi)(例如保證16KB粒度的數(shù)據(jù)一致性),數(shù)據(jù)可以全部都是新數(shù)據(jù)或者全部都是老數(shù)據(jù),不可以出現(xiàn)其他數(shù)據(jù)。
掉電保護要保護什么數(shù)據(jù)?
首先,所有的存儲系統(tǒng)都有兩種基本的功能,即寫入時找到空余的位置和讀取時找到正確的對應數(shù)據(jù)位置。
那么為了維護這樣的功能,存儲系統(tǒng)中都至少有兩種數(shù)據(jù)即真正有效的 用戶數(shù)據(jù)(user data) 和管理用戶數(shù)據(jù)具體位置和狀態(tài)的 元數(shù)據(jù)(metadata) ,舉個例子,在單機文件系統(tǒng)ext中,文件的內(nèi)容就是用戶數(shù)據(jù),而super block和inode數(shù)據(jù)則為元數(shù)據(jù)。
掉電保護的目的是保證存儲系統(tǒng)的整個狀態(tài)在完成上電操作后,主機端看到的數(shù)據(jù)結構和數(shù)據(jù)內(nèi)容在邏輯上完全和掉電前一致,即保證元數(shù)據(jù)和用戶數(shù)據(jù)都被固化在非易失存儲器上(NAND flash)。那在固態(tài)硬盤中,有哪些用戶數(shù)據(jù)和元數(shù)據(jù)需要保存?
1.用戶數(shù)據(jù)
NVMe協(xié)議中,對用戶數(shù)據(jù)的操作有很多種類,例如直接對數(shù)據(jù)操作的寫(write)命令,對用戶數(shù)據(jù)映射關系進行修改的Dataset Management(TRIM)命令和對整盤進行操作的Format及Sanitize命令等,這些操作的結果都是對主機端看到的邏輯數(shù)據(jù)塊內(nèi)的內(nèi)容進行修改,雖然其過程可能并非對NAND上的數(shù)據(jù)進行改動。
2.元數(shù)據(jù)
SSD固件中最重要的元數(shù)據(jù)為Logic address to physical address mapping table,邏輯地址到物理地址的映射表,我們常常稱之為L2P表,根據(jù)設計的不同主要有三種映射方式:塊映射(block mapping),頁映射(page mapping)和混合映射(hybird mapping)。
塊映射是以block為單位進行映射,在邏輯空間到物理空間的映射過程中,最小映射粒度是塊,從而極大的減少了映射表的大小,可以將其存放在SRAM中,假設當前盤的物理空間大小是5TB,其物理塊的大小是366 page * 2 plane * 3 (TLC)* 16KB = 34.3MB,如果以5TB/34.3MB可以獲得152854個映射關系,如果每個映射entry占用8B空間,則其映射表有1194KB,大約1.2MB的空間。
如果我們將其換成3840GB的標準塊設備映射表,每個映射entry依然以8B/4KB計算,其映射表約為7680MB。
當前,為了滿足企業(yè)級應用和云廠商對于IO latency的需求,企業(yè)級SSD通常選用頁映射。
通過計算我們可以得到,大容量SSD page mapping SSD對于DRAM的需求非常巨大,同時在異常掉電過程中,如何儲存這個巨大的元數(shù)據(jù)表,保證其上電后數(shù)據(jù)的一致性,
頁映射
塊映射
如何保護掉電時的數(shù)據(jù)?
保護掉電時的數(shù)據(jù)首先要有能量來源,作為電子設備,除了電源供能外,電池和電容都可以作為額外的供能來源。電池的問題是成本高,而電容的問題是電壓下降快,支撐時間短。當然為了可能在盤的生命周期內(nèi)只會發(fā)生幾次的的異常掉電情況就在每塊盤上都安裝一塊電池,對于數(shù)據(jù)中心是非常不劃算的買賣,同時也非常的不環(huán)保,那么我就就要設計一下固態(tài)硬盤的固件,使其在異常掉電事件發(fā)生時,只需要毫秒級的時間,就可以完成用戶數(shù)據(jù)和元數(shù)據(jù)的整體固化,為下次上電過程提供充足的信息恢復數(shù)據(jù)。
如上圖所示,在一個SSD的PCB上,主要有如上圖所示的6種主要硬件,分別是與主機端連接的接口,現(xiàn)在主流的是PCIe接口,SSD控制器,PMIC電源控制芯片,DRAM,大量的NAND芯片以及電容。
當有主機的正常供電時,電源從PCIe接口供電,從PMIC將5V電壓轉化為Controller、DRAM和NAND使用的1.1V,2.5V和3.3V電壓,通過不同的通路送出,同時通過分壓電路將電容的電壓提升到一個相對較高的數(shù)值(因為電容存儲的電量和電容的電壓值平方成正比),將電量保存在電容中。
根據(jù)上面的公式,我們可以假設電容是1800uF,當充滿電時電容的電壓是36V,那么可以計算出其保存的電量大約是,1.166J。如果當前的最低可用電壓是5V,即電容電壓低于5V時SSD上有些器件已經(jīng)開始不能工作了,則最低可用的電容能量是0.0225J,基本可以忽略不記。
假定SSD的標準功率是25W,最大瞬時功率是30W,那么1.166J的能量可以讓SSD在電容的供能情況下運行多久?
0.04664s,也就是46ms,如果是以30W來算也能撐38ms。
PMIC的選型?
通過上面的介紹,我們可以知道,為了實現(xiàn)異常斷電的保護,我們需要兩個硬件的器件,分別是PMIC和電容。PMIC的主要功能有:
電壓轉換
將供電的12V電壓轉換為SSD PCB板上器件使用的對應電壓。
電容充電
通過分壓電阻確定電容的電壓,并對電容進行充電。
異常掉電檢測
通過對接口電壓輸入的檢測,當接口的電壓下降到12V的90%以下時,產(chǎn)生中斷信號給到SSD controller,并開始使用電容供電
輸出電壓&電流實時監(jiān)測
對于輸出的電路,進行電壓過流欠流,電流過流欠流的保護。
其他高級功能
例如現(xiàn)在許多PMIC芯片可以提供模擬主機端掉電的功能,通過內(nèi)部切斷供電切換到電容供電,并在一定時間后檢測電容電壓的下降情況,從而確定電容的健康程度。
電容如何選型?
市面上的SSD主要有兩種主流的電容,一種是體積較大鋁電解電容,另一種是相對較為小但是相同容量占PCB面積較大的鉭電容:
鋁電容的好處是成本低,耐壓好,鉭電容的優(yōu)點是容量密度大,穩(wěn)定性好,壽命長,但是耐壓差,成本高。在現(xiàn)有的SSD使用壽命內(nèi)(普遍在3-5年),鋁電容雖然容量較差,但是通過提高電容的電壓,可以很好的提高電容存儲電量從而彌補電容密度低的缺點,并且最最重要的是,鋁電容相對于鉭電容便宜太多,在大規(guī)模量產(chǎn)的SSD產(chǎn)品中,能夠節(jié)約非常大的成本。如果有機會拆一拆企業(yè)級的SSD,你會發(fā)現(xiàn)隨著時間的推移,越來越多的廠商選擇使用鋁電容解決熱插拔問題。
電容的容量如何確定?
在選定了電容類型之后,選擇電容的容量是下一步非常重要的工作,也是和SSD固件設計最密切相關的一步。我們上面提到的FTL表,在頁映射的模式下非常大,如果是我們現(xiàn)在主流使用的4TB盤,其映射表大小通常在3.84GB左右,按照我們前面的計算,盤需要在幾十毫秒的時間內(nèi),將3.84GB的數(shù)據(jù)全部寫入盤上,這是不現(xiàn)實的。
我們可以對SSD的后端(從主控到NAND的帶寬)進行計算,通常一個控制器有8-16個連接NAND芯片的channel,每個Channel上可連接16個NAND芯片來算,后端總共可以使能16*16=256個NAND Die同時做program操作,如果TLC的標準Program時間是2.5ms,一次寫入的數(shù)據(jù)量是2plane * 3 (TLC) *16KB = 96KB數(shù)據(jù),則每秒鐘可以寫入9.375GB的數(shù)據(jù)(理論極限),這個數(shù)據(jù)量是在后端沒有任何損耗的情況下,并且按照平均program時間來算的,如果我們按照NAND的使用后期,program時間增長的情況來算,其帶寬最差可以減少到1/3的理論帶寬,在這種情況下,寫入3.84GB的數(shù)據(jù)也需要400ms以上的電容支撐時間,而我們計算出來的電容則只能支持40ms,這還是我們用了1800uF的大電容的情況下提供的時間。
如果保存整個FTL表的策略不可能,有沒有其他方法?
我們先來看一看FTL表上電恢復策略的歷史演進:
- 掃描全盤恢復
- Checkpoint的引入
- snapshot的引入
- P2L的引入
- Snapshot+Journal
- 單獨的Metadata stream
掃描全盤
這是一種最簡單樸素的上電恢復策略,其過程是在寫入數(shù)據(jù)的時候,對每個寫入單位,例如頁,加上一個表示寫入順序的sequence number或者叫version,這個數(shù)字用來表示當前頁的寫入順序。這種方法有一個前提,是用來排序的頁都在一個寫入流中,所以當我們有多個寫入的流,例如冷熱數(shù)據(jù)分離,GC和User data分離的情況,需要先區(qū)分數(shù)據(jù)的流,再區(qū)分頁的順序。
還有一種策略是sequence number策略的簡化版,叫block sequence number,這種策略借助了物理塊內(nèi)寫入順序必然是連續(xù)的規(guī)則,只對block進行排序,block內(nèi)的順序自然按照物理上的順序進行排序,但是這種情況很難應對多流同時寫入的順序排序問題。
sequence number一般被存放在物理頁的額外空間內(nèi),這個空間內(nèi)和上電重建相關的主要信息就是sequence number和當前物理頁對應的邏輯塊的信息(LBA),通過這兩個信息,掃描全盤數(shù)據(jù)即可重新恢復L2P表的大部分信息。
按照上圖所示,如果下面的方框是NAND上真實的寫入順序,即先橫排從左向右寫滿再換行,那么其中有顏色的部分為最新的映射位置,因為按照寫入的順序,后面寫入的LBA是最新的,我們就可以恢復出來L2P表的映射關系。
掃描全盤的策略引入了一個問題,即TRIM命令的恢復問題。
這個問題的解決方法可以是保存一份Valid Page Bitmap,并在掉電的過程中將整體表保存下來,在SSD容量還比較小的時代,保存整個表還算是比較容易的事情,但是到了大容量時代,即使是VPB table,整個表的大小在4TB的情況下會是128MB。
除了TRIM信息沒有辦法恢復的問題,掃描全盤的策略還有另外一個問題,上電恢復時間太長,整個上電恢復除了讀取全盤的AUX區(qū)域信息外,還需要非常長時間的排序和DRAM訪問,通常這個時間都在分鐘級以上,在現(xiàn)有的云使用場景中,應用希望盡可能快的拉起服務,SSD和系統(tǒng)的啟動時間都在向著微秒級發(fā)展,分鐘級別的上電時間顯然是不夠用的。
Checkpoint
Checkpoint是存儲系統(tǒng)和文件系統(tǒng)里常用的概念,即將關鍵數(shù)據(jù)進行備份,用作系統(tǒng)的回滾。在SSD中,checkpoint作為一份完整的L2P表加VPB表,其信息通常周期性的被存放在固定的SSD固件內(nèi)部block上,不與用戶數(shù)據(jù)混雜,同時一般最少保存2份最近的備份,以免一份數(shù)據(jù)損壞,不能恢復。
Checkpoint可以解決大部分的盤上信息的掃描,但是固件不可能每次寫入或者trim或者format時都做一次checkpoint,這樣寫放大就太大了,那如果在Checkpoint沒有cover的位置發(fā)生了掉電怎么辦?
假設我們的用戶數(shù)據(jù)按照順序寫到了如圖的位置,其中CP1的位置系統(tǒng)在其他地方做了checkpoint,后面更新的LBA1和LBA2的紅色數(shù)據(jù)沒有被包含在CP1中,那么通常的做法是,在做過最新的CP生效后,寫入的新數(shù)據(jù)的AUX中包含指向最近一份的CP的指針。
上電順序:
- 通過Sequence number掃描block,獲取最新的正在寫入的block信息
- 通過二分法查找到當前寫入的位置,通過最后一個頁的信息找到CP指針
- 從NAND中Load CP指針指向的位置,將整份CheckPoint加載到內(nèi)存
- 通過CP對應的sequence number找到對應的user data寫入的sequence number
- 從該位置起啟動“全盤掃描”算法,將紅色部分全部更新到內(nèi)存中的L2P表中
- 將Valid Page Bitmap生效到L2P表上
因為有了checkpoint,上電需要掃描的信息大大的減少,但TRIM對應的Valid Page Bitmap依然需要在掉電的過程中保存到NAND上。
Snapshot
所有掉電算法其實都能完成上電L2P表的重建,區(qū)別在于其速度和效率,同時魯棒性更好。這里的Snapshot方法其實原理上和checkpoint相同,但是將其拆分成多個部分分別固化在NAND上。
Snapshot方法首先將整個L2P表均勻的劃分成多個部分,例如圖上的L2P表只有8個LBA,被兩兩分成了4個部分,即CP1,CP2,CP3,和CP4。如果firmware計算下來,每一行user data寫入,觸發(fā)一次CP的寫入是最合算的,那么除了format全盤時寫入的一份空CP外,后面的每一個部分都由user data的寫入數(shù)量觸發(fā)。
上面的例子中,第一行user data寫完時,觸發(fā)了metadata流中的第二個CP1部分的寫入,寫入的是LBA1和LBA2的部分,寫入之后又到了第二行,則寫入了LBA3和LBA4的部分。
大家可以試想一下,這里寫入的LBA1和LBA2是指向哪個物理位置的?其實是指向第一對LBA1和LBA2的位置,即整個NAND分布的第一和第二個page,第二行的LBA1和LBA2并沒有被包含進來,所以在這種算法之下,每個LBA的部分要分別計算開始“全盤掃描”算法的位置,CP1的起始位置是第二行的開始,CP2的起始位置是第三行的開始,而CP3和CP4的起始位置是所有數(shù)據(jù)。
雖然在當前的例子中,看起來掃描全盤的數(shù)據(jù)變多了,但實際上在盤整體運行至穩(wěn)態(tài)后,其掃描數(shù)據(jù)并不會比checkpoint方法多很多。其好處是每次CP運行時不會有太多數(shù)據(jù)需要寫,并且總體上可以很精準的控制user data和metadata的比例,從而更好的控制寫放大和latency。
上電流程:
- 通過block信息掃描到metadata block
- 找到最后一份完整的CP(當前例子是CP2 CP1 CP4 CP3)
- 通過每一份CP的sequence number找到需要“全盤掃描”的起始位置
- 開始全盤掃描更新L2P表
- 更新Valid Page Bitmap表到L2P表
這里同樣面臨的問題是TRIM的Valid Page Bitmap的問題,其數(shù)據(jù)依然需要在掉電過程中保存??傮w上來說,從checkpoint到snapshot的優(yōu)化,引入了固件邏輯復雜度,但是分片的方法可以避免很多在checkpoint過程中掉電的問題,以及避免了觸發(fā)Checkpoint的邏輯點的選擇,固定了user data和metadata的比例,更好的控制寫放大和時延。
P2L的引入
P2L是一種對L2P映射表的反向映射信息,其作用相當于在AUX中保存的LBA的信息的匯總。
前面提到“掃描全盤”算法中需要對每個頁都發(fā)起讀,這個過程是一個非常耗時的過程,而P2L可以將一整個block上的LBA信息進行集中,從而加速掃描全盤的過程。該信息作用更大的地方在于GC,在GC選中源Block時,其上數(shù)據(jù)的有效性也可以通過掃描其AUX并對比L2P表進行確認,但GC本身在穩(wěn)態(tài)時成為最大數(shù)據(jù)量來源,此時能加速GC則對整個盤的性能提升非常有幫助。為了提升GC的效率,通常固件中都會引入P2L信息(物理位置到邏輯塊的反向映射信息)和Valid Bit Table信息(快速選源)。
回到我們的上電重建:
如果我們規(guī)定固件中每4行的用戶數(shù)據(jù)需要一個P2L的page,這個page中保存了上面4行中每個page對應的LBA的信息,這個信息被保存在這個block的最后一個一個page上,則我們可以得到的P2Lpage中的信息就像上圖中的矩陣一樣,P2L自己的LBA信息可以規(guī)定為一個特定的無效值,如0xFFFFFFFE等。
這樣當上電過程中,需要對該區(qū)域進行掃描全盤時,不需要再去讀取每一行的用戶數(shù)據(jù),只需要將P2Lpage的信息讀取即可。如果該page發(fā)生讀錯誤,可以通過掃描全盤算法進行backup。
引入了P2L之后,不但能加速上電時間,還能起到元數(shù)據(jù)保護的作用,另外主要還是GC的速率得到非常大的提升。
Journal的引入
journal是什么?實際上Journal是用一個簡短的元數(shù)據(jù)記錄來保存L2P變化的信息,舉個例子,如果固件做了一筆寫,則L2P中的一個信息做了修改,則Journal中會記錄一次物理頁信息的替換,LBA3421中如果原來指向PPA 12,則新寫入的LBA3421會產(chǎn)生一個journal,類型是寫信息,記錄了LBA,新寫入的PPA信息(LBA和PPA pair)。這里如果是TRIM,則會記錄LBA的信息。
Journal會保存在DRAM或者SRAM中,當湊足一定的數(shù)量后(通常是16KB這樣的NAND可寫入單位),固化到metadata流中。
假設一個Journal page中剛好包含8個寫page的信息,則可以看到寫到4行用戶數(shù)據(jù)的時候,每個CP part前都有一個Journal page,如果Journal page出現(xiàn)在所有有效的CP part之前,則其已經(jīng)被包含在后面的CP part中,可以不需要做update的操作。
Journal同時可以包括trim和write兩種操作的記錄,所以在這種設計下,Valid Page Bitmap是不一定需要的,當然這種Bitmap依然可以起到加速trim的作用,但是在邏輯正確性的層面,其并非是必須的。
其優(yōu)點是顯而易見的,可以完全脫離User data來記錄metadata,但是也有缺點,即引入了Journal所占用的空間,同時不能完全代替P2L的作用,這里P2L的策略和Journal的策略各有優(yōu)劣,可以根據(jù)設計SSD的目標用戶來做權衡,如果想提供更快的上電時間,Journal是更優(yōu)的策略,如果想節(jié)省一定的OP(over provision),則P2L已經(jīng)可以滿足需求。同時,Journal策略可能更匹配多流的設計其流間的上電順序更容易確定。
單獨的Metadata流
我們前面提到的Checkpoint,snapshot,journal信息都是獨立于user data的metadata,他們可以被單獨的放在一個流上(獨立的NAND block上),也可以和用戶數(shù)據(jù)混在一起。多種策略其實在之前的產(chǎn)品中都有實踐,并且都能交付。但是在云場景對QoS要求更加嚴格的今天,多流已經(jīng)成為一個標配,而元數(shù)據(jù)不影響用戶數(shù)據(jù)的時延是一個基本需求,所以從協(xié)議到固件設計都提出了多流的概念。單獨的Metadata流可以引入更加復雜的GC機制,除了為用戶數(shù)據(jù)提供足夠的空間外,元數(shù)據(jù)也要保證數(shù)據(jù)失效后被擦除的速度。
如我們前面看到的snapshot+journal的方案,其數(shù)據(jù)就是被獨立放置在額外的NAND物理空間上。
根據(jù)以上提到的多種L2P元數(shù)據(jù)固化策略,掉電時需要保存的數(shù)據(jù)量也會有所不同。
首先是 write buffer中的數(shù)據(jù) :
由于用戶對IO時延越來越苛刻的要求,現(xiàn)在多數(shù)的廠商將write buffer直接做在Controller的SRAM中,當數(shù)據(jù)從PCIe來的時候,直接fetch到SRAM的好處是速度非???,在4KB的QS1寫測試中,Intel的TLC產(chǎn)品可以達到5-7us的寫時延。當固件在SRAM中收集到足夠的program數(shù)據(jù)時,開始直接向NAND傳輸數(shù)據(jù)。而在此之前,當數(shù)據(jù)完全寫入SRAM的時候,SSD固件就會向CQE中寫入信息,表示write命令完成,雖然此時數(shù)據(jù)還在SRAM中。
從圖上可以看出,當?shù)竭_第二步的時候,host已經(jīng)認為數(shù)據(jù)寫完成,如果此時發(fā)生掉電或者熱插拔現(xiàn)象,SRAM中的數(shù)據(jù)需要通過電容電量固化到NAND中。這個數(shù)據(jù)量有多少,各家各不相同,但是基本的計算思路應該是相同的,即需要足夠的數(shù)據(jù)量保證帶寬。
為什么寫入buffer的大小和帶寬有關?因為第一,controller和NAND的關系是1對多的關系,即分發(fā)的關系,每一個NAND Die是否在空閑狀態(tài),是否出錯,是否正在read或者write是需要管理的,而在數(shù)據(jù)發(fā)送出去之前,是需要hold在buffer中的。第二,NAND的program是有一定出錯的概率的,如果發(fā)生的program錯誤,有兩種常見的處理方式:
- program過程中不釋放buffer,等到program返回正確狀態(tài)才釋放
- program開始即釋放buffer,如果program失敗按照read失敗處理
通常第一種方式更安全,所以企業(yè)級SSD一般會選擇第一種錯誤處理方式,而這種方式帶來的問題是需要hold更長時間的write buffer,需要更大的SRAM即更多的成本。在成本和性能之間,設計者需要做一個平衡。
所有在SRAM中的數(shù)據(jù)幾乎都要在掉電時保存到NAND上,假設我們有1MB的數(shù)據(jù)需要保存,就要將數(shù)據(jù)的信息計算到電容的電量中。
GC寫buffer的處理
通常GC的流程是,從GC源block中讀取一段有效數(shù)據(jù),寫入到新的GC流block中,這個過程中有一些數(shù)據(jù)會緩存在SRAM或者DRAM的buffer中。這段數(shù)據(jù)是否需要在掉電過程中固化?答案是不需要,因為數(shù)據(jù)的來源來自于源block,這里需要注意的是,上電過程中的L2P表的重建過程會需要特別注意,不要將映射指向GC的目的block,這里有很多的細節(jié)需要設計,在不同的L2P表GC update策略中會有不同的做法。不過可以確認的是,在掉電過程中不需要對GC buffer做額外的處理即可。
元數(shù)據(jù)的處理:
我們前面提到了多種L2P表的固化方法,他們是為正常掉電設計的,異常掉電過程中,一般來說如果是消費級產(chǎn)品,不加電容的話,不論使用全盤掃描還是checkpoint,都可以達到讓SSD重新用起來的目標。只是write buffer中的數(shù)據(jù)不能保證恢復。
在企業(yè)級SSD中,雖然保底使用全盤掃描總能恢復當前L2P表,但是其速度會非常慢,所以通常我們把最后緩存在Metadata buffer中的數(shù)據(jù),例如未寫入NAND的Journal,dirty Valid Page Bitmap等信息同時寫入NAND,其數(shù)據(jù)量通常不超過10MB。
我們假設我們設計的企業(yè)級產(chǎn)品有30MB的用戶數(shù)據(jù)buffer,10MB的元數(shù)據(jù)buffer需要寫入,那么需要多大的電容呢?
我們首先需要計算后端帶寬:
假設我們的controller有16個channel,每個channel上都掛有16個NAND Die,則共有256個獨立的物理die,也就是一個super page有256個獨立的physical page。die是NAND可以處理讀寫擦指令的最小邏輯單位,其內(nèi)部是不能并行執(zhí)行其他指令的(可以通過multiplane write等技術并行執(zhí)行相同命令,但不可同時執(zhí)行不同命令,因為其邏輯電路是per die設計的),所以后端帶寬如果全都執(zhí)行program命令的話,在TLC的2plane NAND上,可以并行執(zhí)行256*96KB的program,即24MB。當然這只是一個理論值,在實際運行過程中,還有其他各種損耗,Controller傳輸?shù)碾A梯效應,整體SSD功耗限制等,最終能有效利用其中的80%就算是很好的帶寬利用率了。
假設總數(shù)據(jù)量是30MB+10MB=40MB,后端全die一次的program量是24MB,加上NAND上on going的program,總共需要所有Die在電容支持下program 3次完整的Tprog。
這里如果我們按照TLC NAND spec給出的最差情況,一個program完成的Max time是7ms,那么總共算下來需要3*7=21ms的總時間。前面我們已經(jīng)計算過大概30w的SSD在1800uF的電容下可以運行多久,相信通過這個時間的比較大家也知道,只要電容運行時間超過program需要的時間,在理論上這個方案就是可行的。
但實際的過程中,我們還需要考慮很多其他的問題,例如如果NAND在做erase全盤的操作,這時掉電需要對NAND發(fā)送erase suspend命令并等到命令返回成功,如果盤上寫入數(shù)據(jù)出錯,是否需要重寫等問題。我們這里僅做掉電處理概念性的介紹,不做詳細的討論,如果您有興趣,可以聯(lián)系我私下討論這些掉電時的異常處理。
通常的處理是我們按照計算出來的需要時間的2-3倍來設計電容,這樣即使發(fā)生了異常,大概率還是能在電容涵蓋的時間內(nèi)完成保護。
掉電的固件設計
完成了硬件的設計和參數(shù)的確定后,固件的設計其實主要還是配合硬件完成工作。首先是中斷設計。
掉電中斷設計
異常掉電時,PMIC會首先產(chǎn)生一個中斷信號脈沖傳遞給controller,當前絕大部分的controller使用了ARM核,使用的中斷可以選擇的是IRQ類型和FIQ類型。通常而言,掉電事件的優(yōu)先級在整個系統(tǒng)中是最高的,但是由于SSD固件的特殊性,我所經(jīng)歷過的一些項目都沒有選擇可打斷中斷的FIQ,而選擇了讓其他中斷運行完成后再進入的IRQ。這里的前提假設有兩個。第一,在設計其他中斷處理函數(shù)時,是否設計為可打斷的函數(shù),通常我們認為中斷處理函數(shù)內(nèi)容非常簡單,時間非常短,沒有同步行為,則會設計時不會考慮被打斷,資源也沒有鎖等處理機制。第二,在時間上,異常掉電時間是可以容忍微秒級別的延遲的,但是由于其對各種硬件資源的獨占性需求,希望在掉電過程中其他資源使用者能及時釋放資源。
掉電中斷通常設計為兩部分:
- 通知硬件中斷正在進行的PCIe傳輸,關閉其他中斷源
- 設置全局信號通知所有核上運行固件,發(fā)生掉電中斷
掉電固件設計
SSD上的資源釋放是掉電處理中的關鍵,SSD上的主要資源是Controller的CPU資源,DRAM資源(L2P表的訪問修改權限等),SRAM資源,NAND控制權和其他一些輔助器件的資源。
通常SSD的固件任務,除了IO之外都會設計為可被調(diào)度的task狀態(tài)機,例如GC任務就會被設計為多個階段,從觸發(fā),到選源,到讀取,到寫入,到L2P更新,都會有自己獨立的狀態(tài),同時獨立的狀態(tài)中會將數(shù)據(jù)拆分,例如數(shù)據(jù)可能會以256KB為單位進行操作等。這樣設計的好處是每個子任務都可以獨立完成,在任務的中間可以對全局的掉電狀態(tài)進行檢查,并且任務的間隙中對硬件和固件資源沒有占用,相當于每個子任務狀態(tài)機的一個狀態(tài)結束,都會釋放資源。這種設計方案的好處是,對于IO時延和異常掉電都有益處,但是設計復雜度非常高,并且要求設計者在設計任何其他task時,都要時刻考慮狀態(tài)機的設計,考慮掉電時的資源占用問題,給設計者增加了復雜度。
與之相應的,設計掉電流程時,設計者會盡可能的少占用runtime時的任務所使用的資源,例如掉電過程可以使用一個單獨reserved super block作為寫入的目的block,可以使用一段自定義的L2P表專門映射30MB的用戶數(shù)據(jù)等。
掉電過程中如果有足夠的電容,則可以將30MB+10MB的數(shù)據(jù)都寫入TLC block中,但是當數(shù)據(jù)量大,或者NAND寫入過慢時,又不能增加電容容量,可以將TLC(或QLC)NAND當做SLC來使用,尤其相比于QLC,SLC的后端帶寬可以顯著增加,從而使SSD在不增加硬件成本的情況下依然保證掉電數(shù)據(jù)不丟失。
如果使用TLC作為掉電保護的目標block:
- 收到全局的掉電處理狀態(tài)
- 完成當前核上的runtime task分片
- 切入掉電處理task
- 發(fā)送erase suspend指令處理正在erase的die
- 等待所有TLC上的program完成,將所有read指令進行abort
- 將所有buffer中的數(shù)據(jù)(30MB)寫入掉電處理block,補齊到RAID
- 等待寫狀態(tài)返回
- 將Dirty Journal及Dirty Valid Page Bitmap(10MB)寫入 目標block
- 等待寫狀態(tài)返回
- 等待電容釋放完電量
如果使用SLC作為掉電保護
- 收到全局的掉電處理狀態(tài)
- 完成當前核上的runtime task分片
- 切入掉電處理task
- 發(fā)送erase suspend和write、read abort指令(需NAND支持)
- 等待abort結束
- 將write buffer中數(shù)據(jù)寫入SLC block
- 等待寫狀態(tài)返回
- 將Dirty Journal及Dirty Valid Page Bitmap(10MB)寫入SLCblock
- 等待寫狀態(tài)返回
- 記錄SLCblock的位置到root信息中
可以看出,用戶數(shù)據(jù)要先于元數(shù)據(jù)信息寫入,這個也非常好理解,元數(shù)據(jù)必須包含新寫入的映射關系,否則上電恢復的過程中將丟掉這些信息。
上電恢復過程
上電的恢復過程與掉電的過程其實正好相反:
- 掃描所有的block以確定其所在的流和順序
- 從掉電保存信息的block上恢復write buffer中的信息和metadata信息
- 從metadata流中恢復L2P表
- 將write buffer中的信息重新寫入正常流
- 確認電容充電完成且電容狀態(tài)健康
- 回復host CSTS.RDY標志
上電的過程中需要注意,可以將上電整個過程分成三個部分,第一部分是Load信息的過程,第二部分是將掉電信息中的user data和metadata重新寫入正常路徑,第三部分是給host Ready flag,從而讓host可以開始發(fā)送新的IO,而盤也可以正常處理下一次異常掉電。
這里需要注意的是一種叫back to back的掉電,即在上電的第一部分和第二部分中再次發(fā)生異常掉電的處理。這種處理要求整個上電的過程是歸一化的,也就是說當再次發(fā)生掉電時,下次上電不需要占用額外的資源,可以統(tǒng)一處理。
掉電過程中的NAND錯誤
NAND是一種不穩(wěn)定的介質(zhì),所以有可能在掉電保存信息的過程中,發(fā)生了NAND介質(zhì)錯誤,或者在掉電后過了很長一段時間才上電,在此期間發(fā)生了介質(zhì)錯誤,那么是否可以像正常的program或者read error一樣處理呢?
掉電處理的設計有一個通用性的原則就是,能在上電過程中處理的事情,就不要占用電容的電量在掉電過程處理,如果有額外的電量,可以處理。
如果在掉電過程中發(fā)現(xiàn)了program狀態(tài)出錯,這時的信息還在我們的buffer里,有兩種可供選擇的方法,第一是重新再次program,第二是等上電時像read error一樣用RAID來糾錯。選擇哪種方法要根據(jù)NAND出錯的概率來計算,如果program fail和UECC發(fā)生在同一個RAID set上的概率低于產(chǎn)品設計時的UECC允許概率,則可以將其當做read error來統(tǒng)一處理。
異常掉電的Debug
異常掉電的debug可以單獨的拿出來寫一篇文章,因為異常掉電的處理面臨非常多種的復雜情況,可以說盤上的固件在做任何Task時都有可能觸發(fā)異常掉電,所以要寫UT來測試異常掉電可能會非常復雜。而任何同步操作導致的資源釋放變慢,掉電處理task接管SSD時間晚等問題,都有可能造成SSD在電容電量之內(nèi)沒能處理完所有數(shù)據(jù),導致上電過程失敗。
首先,掉電過程在結束時需要一個明顯的標識來確定掉電task完整做完。
其次,掉電過程需要記錄足夠的log信息來供工程師debug使用。
最后,通過控制PMIC來進行假掉電事件的模擬可以抓到很多問題。
異常掉電處理的發(fā)展和展望
異常掉電是SSD固件中一個比較難設計好的feature,并且通過復雜的設計保證的很多功能在現(xiàn)實的應用場景中也很難遇到,一旦出現(xiàn)了掉電丟數(shù)據(jù)的情況,通常損失非常慘重,輕則丟失一些重要客戶,重則造成工程甚至人身安全的損失。隨著單盤的容量越來越大,L2P表的體積也越來越大,其上電時間因而也線性的增加了。
1.通過改變L2P表的結構來優(yōu)化
L2P表是一個線性映射表,如果我們將其與文件或者對象相結合,是否可以通過樹或者其他形式進行直接對映射?
2.通過改變L2P表固化的介質(zhì)
相變存儲器的引入和多層的L2P表merge設計可能會是一個固化L2P表的新思路,這里以Optane為代表的非易失存儲器可以用來存儲L2P表,這樣SSD中就徹底的解決了L2P表固化問題。
-
NAND
+關注
關注
16文章
1666瀏覽量
135931 -
熱插拔
+關注
關注
2文章
214瀏覽量
37148 -
SSD
+關注
關注
20文章
2833瀏覽量
117126 -
固態(tài)硬盤
+關注
關注
12文章
1442瀏覽量
57222 -
掉電保護
+關注
關注
2文章
25瀏覽量
15801
發(fā)布評論請先 登錄
相關推薦
評論