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