1、Linux 虛擬文件系統(tǒng)介紹
在 Linux 系統(tǒng)中一切皆文件,除了通常所說的狹義的文件以外,目錄、設備、套接字和管道等都是文件。
文件系統(tǒng)在不同的上下文中有不同的含義:
在存儲設備上組織文件的方法,包括數(shù)據(jù)結構和訪問方法,到存儲設備。
按照某種文件系統(tǒng)類型格式化的一塊存儲介質。我們常說在某個目錄下掛載或卸載文件系統(tǒng), 這里的文件系統(tǒng)就是這種意思。
內核中負責管理和存儲文件的模塊,即文件系統(tǒng)模塊。
Linux文件系統(tǒng)的架構如下圖所示,分為用戶空間、內核空間和硬件3個層面:
注意:上圖中方塊對齊關系,很多時候我們分不清內核文件系統(tǒng)中 "cache" 和 "buffer" 的區(qū)別,畢竟兩者都可以翻譯為 "緩存區(qū)",但是從圖中,就可以很清晰的看出所謂的 "cache" 其實指的就是圖中的 "頁緩存" 它是針對文件來說的,除了 "DAX"(直接訪問方式的設備)它不使用 "緩存",其他的閃存類,塊設備類設備都會使用到 "頁緩存" 也就是 "cache",而 "buffer" 其實指的就是圖中的 "塊緩存" 它是針對塊設備的。
1.1、硬件層面
外部存儲設備分為塊設備、閃存和 NVDIMM 設備 3 類,塊設備主要有以下兩種:
機械硬盤:機械硬盤的讀寫單位是扇區(qū)。訪問機械硬盤的時候,需要首先沿著半徑 方向移動磁頭尋找磁道,然后轉動盤片找到扇區(qū)。
閃存類塊設備:使用閃存作為存儲介質,里面的控制器運行固化的驅動程序,驅動 程序的功能之一是閃存轉換層(Flash Translation Layer,F(xiàn)TL),把閃存轉換為塊設備, 外表現(xiàn)為塊設備。常見的閃存類塊設備是在個人計算機和筆記本電腦上使用的固態(tài)硬盤 splid State Drives,SSD),以及在手機和平板電腦上使用的嵌入式多媒體存儲卡(embedded Multi Media Card,eMMc)和通用閃存存儲(Universal Flash Storage,UFS)。閃存類塊設備相對機械硬盤的優(yōu)勢是:訪問速度快,因為沒有機械操作:抗振性很高, 便于攜帶。
閃存(Flash Memory)的主要特點如下:
在寫入數(shù)據(jù)之前需要擦除一個擦除塊,因為向閃存寫數(shù)據(jù)只能把一個位從 1 變成 0,不能從 0 變成 1,擦除的目的是把擦除塊的所有位設置為 1
一個擦除塊的最大擦除次數(shù)有限,NOR閃存的擦除塊的最大擦除次數(shù)是 10^4~10^3, NAND 閃存的擦除塊的最大擦除次數(shù)是 10^3~10^6。
閃存按存儲結構分為 NAND 閃存和 NOR 閃存,兩者的區(qū)別如下:
NOR閃存的容量小,NAND 閃存的容量大。
NOR 閃存支持按字節(jié)尋址,支持芯片內執(zhí)行(eXecute In Place,XIP),可以直接 在閃存內執(zhí)行程序,不需要把程序讀到內存中; NAND 閃存的最小讀寫單位是頁或子頁, 一個擦除塊分為多個頁,有的 NAND 閃存把頁劃分為多個子頁。
NOR 閃存讀的速度比 NAND 閃存塊,寫的速度和擦除的速度都比 NAND 閃存慢
NOR 閃存沒有壞塊;NAND 閃存存在壞塊,主要是因為消除壞塊的成本太高 NOR 閃存適合存儲程序,一般用來存儲引導程序比如 uboot 程序;NAND 閃存適 合存儲數(shù)據(jù)。
為什么要針對閃存專門設計文件系統(tǒng)?主要原因如下:
NAND 閃存存在壞塊,軟件需要識別并且跳過壞塊。
需要實現(xiàn)損耗均衡( wear leveling),損耗均衡就是使所有擦除塊的擦除次數(shù)均衡, 避免一部分擦除塊先損壞。
機械硬盤和 NAND 閃存的主要區(qū)別如下:
機械硬盤的最小讀寫單位是扇區(qū),扇區(qū)的大小一般是 512 字節(jié):NAND 閃存的最 小讀寫單位是頁或子頁。
機械硬盤可以直接寫入數(shù)據(jù):NAND 閃存在寫入數(shù)據(jù)之前需要擦除一個擦除塊。
機械硬盤的使用壽命比 NAND 閃存長:機械硬盤的扇區(qū)的寫入次數(shù)沒有限制:NAND 閃存的擦除塊的擦除次數(shù)有限。
機械硬盤隱藏壞的扇區(qū),軟件不需要處理壞的扇區(qū):NAND 閃存的壞塊對軟件可 見,軟件需要處理壞塊。
NVDIMM(Nonn-Volatile DIMM,非易失性內存:DIMM 是 Dual-Inline-Memory-Modules 的縮寫,表示雙列直插式存儲模塊,是內存的一種規(guī)格)設備把 NAND 閃存、內存和超級電容集成到一起,訪問速度和內存一樣快,并且斷電以后數(shù)據(jù)不會丟失。在斷電的瞬間, 超級電容提供電力,把內存中的數(shù)據(jù)轉移到 NAND 閃存。
1.2、內核空間層面
在內核的目錄 fs 下可以看到,內核支持多種文件系統(tǒng)類型。為了對用戶程序提供統(tǒng)一的 文件操作接口,為了使不同的文件系統(tǒng)實現(xiàn)能夠共存,內核實現(xiàn)了一個抽象層,稱為虛擬文件系統(tǒng)(Virtual File System,VFS),也稱為虛擬文件系統(tǒng)切換(Virtual Filesystem Switch,VFS) 文件系統(tǒng)分為以下幾種。
塊設備文件系統(tǒng),存儲設備是機械硬盤和固態(tài)硬盤等塊設備,常用的塊設備文件 系統(tǒng)是 EXT 和 btrfs。EXT 文件系統(tǒng)是 Linux 原創(chuàng)的文件系統(tǒng),目前有 3 個 成版本:EXT[2-4]。
閃存文件系統(tǒng),存儲設備是 NAND 閃存和 NOR 閃存,常用的閃存文件系統(tǒng)是 JFFS2 ,(日志型閃存文件系統(tǒng)版本2, Journalling Flash File System version2)和 UBIFS(無序區(qū)塊鏡像文件系統(tǒng), Unsorted Block Image File System)。內存文件系統(tǒng)的文件在內存中,斷電以后文件丟失,常用的內存文件系統(tǒng)是 tmpfs, 用來創(chuàng)建臨時文件。
偽文件系統(tǒng),是假的文件系統(tǒng),只是為了使用虛擬文件系統(tǒng)的編程接口,常用的 偽文件系統(tǒng)如下所示:
sockfs,這種文件系統(tǒng)使得套接字(socket)可以使用讀文件的接口 read 接收報文, 使用寫文件的接口 write 發(fā)送報文。
proc 文件系統(tǒng),最初開發(fā) proc 文件系統(tǒng)的目的是把內核中的進程信息導出到用戶空間, 后來擴展到把內核中的任何信息導出到用戶空間,通常把 proc 文件系統(tǒng)掛載在目錄 "proc" 下。
sysfs,用來把內核的設備信息導出到用戶空間,通常把 sysfs 文件系統(tǒng)掛載在目錄 "/sys"下。
hugetlbfs,用來實現(xiàn)標準巨型頁。
cgroup 文件系統(tǒng),控制組(control group cgroup)用來控制一組進程的資源, cgroup 文件系統(tǒng)使管理員可以使用寫文件的方式配置 cgroup。
cgroup2 文件系統(tǒng), cgroup2 是 cgroup 的第二個版本, cgroup2 文件系統(tǒng)使管理員可 以使用寫文件的方式配置 cgroup2。
這些文件系統(tǒng)又各自有著相關的特性:
頁緩存:訪問外部存儲設備的速度很慢,為了避免每次讀寫文件時訪問外部存儲設備,文件系統(tǒng)模塊為每個文件在內存中創(chuàng)建了一個緩存,因為緩存的單位是頁,所以稱為頁緩存。
塊設備層:塊設備的訪問單位是塊,塊大小是扇區(qū)大小的整數(shù)倍。內核為所有塊設備實現(xiàn)了統(tǒng)一 的塊設備層。
塊緩存:為了避免每次讀寫都需要訪問塊設備,內核實現(xiàn)了塊緩存,為每個塊設備在內存中創(chuàng) 建一個塊緩存。緩存的單位是塊,塊緩存是基于頁緩存實現(xiàn)的。
IO 調度器:訪問機械硬盤時,移動磁頭尋找磁道和扇區(qū)很耗時,如果把讀寫請求按照扇區(qū)號排序, 可以減少磁頭的移動,提高吞吐量。IO 調度器用來決定讀寫請求的提交順序,針對不同的 使用場景提供了多種調度算法:NOOP(No Operation)、CFQ(完全公平排隊, Complete Fair Queuing)和 deadline(限期)。NOOP 調度算法適合閃存類塊設備,CFQ 和 deadline調度算 法適合機械硬盤。
塊設備驅動程序:每種塊設備需要實現(xiàn)自己的驅動程序。
內核把閃存稱為存儲技術設備( Memory Technology Device,MTD),為所有閃存實現(xiàn) 了統(tǒng)一的 MTD 層,每種閃存需要實現(xiàn)自己的驅動程序。針對 NVDIMM 設備,文件系統(tǒng)需要實現(xiàn) DAX(Direct Access直接訪問:X 代表 eXciting,沒有意義,只是為了讓名字看起來酷),繞過頁緩存和塊設備層,把 NVDIMM 設備里面的內存直接映射到進程或內核的虛擬地址空間。
libnvdimm 子系統(tǒng)提供對 3 種 NVDIMM 設備的支持:持久內存(persistent memory,PMEM) 模式的 NVDIMM 設備,塊設備(block,BLK)模式的 NVDIMM 設備,以及同時支持PMEM 和 BLK 兩種訪問模式的 NVDIMM 設備。PMEM 訪問模式是把 NVDIMM 設備當作內存,BLK 訪問模式是把 NVDIMM 設備當作塊設備。每種 NVDIMM 設備需要實現(xiàn)自己的驅動程序。
2、下一代存儲技術NVIDMM
NVDIMM (Non-Volatile Dual In-line Memory Module) 是一種可以隨機訪問的, 非易失性內存。非易失性內存指的是即使在不通電的情況下, 數(shù)據(jù)也不會消失。因此可以在計算機掉電 (unexpected power loss), 系統(tǒng)崩潰和正常關機的情況下, 依然保持數(shù)據(jù)。NVDIMM 同時表明它使用的是 DIMM 封裝, 與標準DIMM 插槽兼容, 并且通過標準的 DDR總線進行通信。考慮到它的非易失性, 并且兼容傳統(tǒng)DRAM接口, 又被稱作Persistent Memory。
2.1、種類
目前, 根據(jù) JEDEC 標準化組織的定義, 有三種NVDIMM 的實現(xiàn)。分別是:
NVDIMM-N
指在一個模塊上同時放入傳統(tǒng) DRAM 和 flash 閃存,計算機可以直接訪問傳統(tǒng) DRAM。支持按字節(jié)尋址,也支持塊尋址。通過使用一個小的后備電源,為在掉電時數(shù)據(jù)從 DRAM 拷貝到閃存中提供足夠的電能;當電力恢復時再重新加載到 DRAM 中。
NVDIMM-N示意圖
NVDIMM-N 的主要工作方式其實和傳統(tǒng) DRAM是一樣的。因此它的延遲也在10的1次方納秒級。而且它的容量,受限于體積,相比傳統(tǒng)的 DRAM 也不會有什么提升。
同時它的工作方式決定了它的 flash 部分是不可尋址的,而且同時使用兩種介質的作法使成本急劇增加,但是 NVDIMM-N 為業(yè)界提供了持久性內存的新概念。目前市面上已經有很多基于NVIMM-N的產品。
NVDIMM-F
指使用了 DRAM 的DDR3或者 DDR4 總線的flash閃存。我們知道由 NAND flash 作為介質的 SSD,一般使用SATA,SAS 或者PCIe 總線。使用 DDR 總線可以提高最大帶寬,一定程度上減少協(xié)議帶來的延遲和開銷,不過只支持塊尋址。
NVDIMM-F 的主要工作方式本質上和SSD是一樣的,因此它的延遲在 10的1次方微秒級。它的容量也可以輕松達到 TB 以上。
NVDIMM-P
這是一個目前還沒有發(fā)布的標準 (Under Development),預計將與 DDR5 標準一同發(fā)布。按照計劃,DDR5將比DDR4提供雙倍的帶寬,并提高信道效率。這些改進,以及服務器和客戶端平臺的用戶友好界面,將在各種應用程序中支持高性能和改進的電源管理。
NVDIMM-P 實際上是真正 DRAM 和 flash 的混合。它既支持塊尋址, 也支持類似傳統(tǒng) DRAM 的按字節(jié)尋址。它既可以在容量上達到類似 NAND flash 的TB以上, 又能把延遲保持在10的2次方納秒級。
通過將數(shù)據(jù)介質直接連接至內存總線,CPU 可以直接訪問數(shù)據(jù),無需任何驅動程序或 PCIe 開銷。而且由于內存訪問是通過64 字節(jié)的 cache line,CPU 只需要訪問它需要的數(shù)據(jù),而不是像普通塊設備那樣每次要按塊訪問。
Intel 公司在2018年5月發(fā)布了基于3D XPoint 技術的Intel Optane DC Persistent Memory。可以認為是NVDIMM-P 的一種實現(xiàn)。
Intel Optane DC Persistent Memory
2.2、硬件支持
應用程序可以直接訪問NVDIMM-P, 就像對于傳統(tǒng) DRAM那樣。這也消除了在傳統(tǒng)塊設備和內存之間頁交換的需要。但是向持久性內存里寫數(shù)據(jù)是和向普通DRAM里寫數(shù)據(jù)共享計算機資源的。包括處理器緩沖區(qū), L1/L2緩存等。
需要注意的是, 要使數(shù)據(jù)持久, 一定要保證數(shù)據(jù)寫入了持久性內存設備, 或者寫入了帶有掉電保護的buffer。軟件如果要充分利用持久性內存的特性, 指令集架構上至少需要以下支持:
寫的原子性
表示對于持久性內存里任意大小的寫都要保證是原子性的, 以防系統(tǒng)崩潰或者突然掉電。IA-32 和 IA-64 處理器保證了對緩存數(shù)據(jù)最大64位的數(shù)據(jù)訪問 (對齊或者非對齊) 的寫原子性。因此, 軟件可以安全地在持久性內存上更新數(shù)據(jù)。這樣也帶來了性能上的提升, 因為消除了copy-on-write 或者 write-ahead-logging 這種保證寫原子性的開銷。
高效的緩存刷新(flushing)
出于性能的考慮, 持久性內存的數(shù)據(jù)也要先放入處理器的緩存(cache)才能被訪問。經過優(yōu)化的緩存刷新指令減少了由于刷新 (CLFLUSH) 造成的性能影響。
a. CLFLUSHOPT 提供了更加高效的緩存刷新指令
b. CLWB (Cache Line Write Back) 指令把cache line上改變的數(shù)據(jù)寫回內存 (類似CLFLUSHOPT),但是無需讓這條 cache line 轉變成無效狀態(tài)(invalid, MESI protocol),而是轉換成未改變的獨占狀態(tài)(Exclusive)。CLWB 指令實際上是在試圖減少由于某條cache line刷新所造成的下次訪問必然的cache miss。
提交至持久性內存(Committing to Persistence)
在現(xiàn)代計算機架構下,緩存刷新的完成表明修改的數(shù)據(jù)已經被回寫至內存子系統(tǒng)的寫緩沖區(qū)。但是此時數(shù)據(jù)并不具有持久性。為了確保數(shù)據(jù)寫入持久性內存,軟件需要刷新易失性的寫緩沖區(qū)或者在內存子系統(tǒng)的其他緩存。新的用于持久性寫的提交指令 PCOMMIT 可以把內存子系統(tǒng)寫隊列中的數(shù)據(jù)提交至持久性內存。
非暫時store操作的優(yōu)化(Non-temporal Store Optimization)
當軟件需要拷貝大量數(shù)據(jù)從普通內存到持久性內存中時(或在持久性內存之間拷貝), 可以使用弱順序, 非暫時的store操作 (比如使用MOVNTI 指令)。因為Non-temporal store指令可以隱式地使要回寫的那條cache line 失效, 軟件就不需要明確地flush cache line了(see Section 10.4.6.2. of Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1)。
小結
上面介紹了NVDIMM 的幾種實現(xiàn)方式,以及為了發(fā)揮NVDIMM-P 的性能所做的硬件上的優(yōu)化和支持。下面會繼續(xù)介紹軟件方面的支持,包括編程模型、編程庫、SPDK方面的支持等。
在上篇的 NVDIMM介紹中,我們講解了NVDIMM幾種硬件上的實現(xiàn)方式,以及為了支持和優(yōu)化性能所做的硬件上的改變。接下來讓我們來討論一下為了充分發(fā)揮NVDIMM的性能,軟件方面做了哪些支持。有些人可能會有疑問, 為什么用起來這么麻煩?既然是持久性內存,不是應該關機什么樣, 開機什么樣, 就可以了嗎?其實目前來看, 這種想法還不會變?yōu)楝F(xiàn)實。因為除了DRAM是易失性的,比如 cache,寄存器這種也是易失性的。僅僅把內存做成持久性的也不能達成這樣的目的。另一個問題是, memory leak。如果發(fā)生了內存泄漏,重啟一下就好了。那如果是持久性內存的泄漏呢?這也是一個很棘手的問題。Pmem有些方面類似于內存,也有些方面類似于存儲。但是,通常上我們不會認為Pmem能夠替代內存或存儲。其實,可以把它看作是一種補充,填補了內存和存儲之間巨大的差異。
SPDK 在 17.10 中開始引入對于Pmem的支持。Pmem在SPDK的bdev層暴露為一個塊設備,使用快設備接口和上層進行通信。如下圖所示。
從圖中我們可以看到libpmemblk 把塊操作轉換成了字節(jié)操作。它是怎么做到的呢?在介紹libpmemblk 和 它背后的PMDK之前, 我們了解一下基礎知識。
mmap和DAX
首先,我們來看傳統(tǒng)的I/O方式, 即緩存I/O (Buffered I/O). 大多數(shù)操作系統(tǒng)默認的IO操作方式都是緩存IO。該機制使IO數(shù)據(jù)緩存在操作系統(tǒng)的page cache 中, 也就是說, 數(shù)據(jù)會被先拷貝到操作系統(tǒng)的內核空間的緩沖區(qū)中,然后才會從內核空間的緩沖區(qū)拷貝到指定的用戶地址空間。
在Linux 中, 這種訪問文件的方式就是通過read/write 系統(tǒng)調用來實現(xiàn),如上圖。接下來, 我們比較一下內存映射IO mmap()。
接下來, 我們比較一下內存映射IO mmap()。
通過mmap獲得了對應文件的一個指針,然后就像操作內存一樣進行賦值或者做memcpy/strcpy. 這種我們稱之為load/store操作(這種操作一般需要msync、fsync來落盤)。
mmap因為建立了文件到用戶空間的映射關系,可以看作是把文件直接拷貝到用戶空間,減少了一次數(shù)據(jù)拷貝。但是mmap依然需要依靠page cache。
講完了mmap,那么DAX是什么呢?DAX即direct access,這個特性是基于mmap的。而DAX的區(qū)別在于完全不需要page cache,直接對存儲設備訪問,所以它就是為了NVDIMM而生的。應用對于mmap的文件操作,是直接同步到NVDIMM上的。DAX目前在XFS, EXT4, Windows的 NTFS 上都已經支持。需要注意的是, 使用這個模式,要對應用程序或者文件系統(tǒng)進行修改。
2.3、NVM Programming Model
NVM Programming Model 大致定義了三種使用方式。
2.3.1 最左邊Management 主要是通過driver提供的API對NVDIMM進行管理, 比如查看容量信息、健康狀態(tài)、固件版本、固件升級、模式配置等等。
2.3.2 中間, 作為存儲快設備使用, 使用支持NVDIMM driver 的文件系統(tǒng)和內核, 應用程序不用做任何修改,通過標準文件接口訪問NVDIMM。
2.3.3 第三種, 基于文件系統(tǒng)的DAX特性,通過load/store操作,不需要page cache,同步落盤,沒有系統(tǒng)調用, 沒有中斷。這也是NVM Programming Model 的核心, 能夠充分釋放NVDIMM的性能優(yōu)勢。但它的缺點在于,應用程序可能需要做一下改變。
PMDK
libpmemblk 實現(xiàn)了一個駐留在pmem中的同樣大小的塊的數(shù)組。里面每個塊對于突然掉電,程序崩潰等情況依然保持原子事務性。libpmemblk是基于libpmem庫的,libpmem是PMDK中提供的一個更底層的庫, 尤其是對于flush的支持。它能夠追蹤每次對pmem的store操作,并保證數(shù)據(jù)落盤為持久性數(shù)據(jù)。
除此以外, PMDK 還提供了其他編程庫, 比如 libpmemobj,libpmemlog,libvmmalloc 等。感興趣可以訪問其主頁獲取更多信息。
結語
至此,對于NVDIMM硬件和軟件上的不同, 大家都有了一個大致的認識。Intel 在2018年5月發(fā)布了基于3D XPoint 技術的Intel Optane DC Persistent Memory,引發(fā)了NVDIMM爆點。
2.4、上述內容可做如下的概述
NVIDMM分類
NVIDMM-N:memory mapped DRAM,提供字符訪問接口,在三種產品中性能最好,容量最小
NVDIMM-F:memory mapped Flush,只提供塊設備接口。Nand Flush直接鏈接到Memory controller channel。
NVIDMM-P:Under Development,提供塊設備和字符設備訪問接口。
特性
NVDIMM-N:NVDIMM-N既可以用作緩存,又可以作為塊存儲設備來用。典型代表是類似intel 的AEP。
NVIDMM-F:不同于NVIDMM-N主要用作緩存,NVIDMM-F主要用作存儲。可以用來快速構建高密度的內存池存儲池。
2.4.1 構建基于NVDMM的文件系統(tǒng)
門為PMEM設計的文件系統(tǒng)是NOVA Filesystem,感興趣的讀者可以參考NOVA的github。
ZUFS作為來自于NetApp的一個項目,ZUFS的全稱是Zero-copy User Filesystem。聲稱是實現(xiàn)了完全的zero-copy,甚至文件系統(tǒng)的metadata都是zero-copy的。ZUFS主要是為了PMEM設計,但是也可以支持傳統(tǒng)的磁盤設備,相當于是FUSE的zero-copy版本,是對FUSE的性能的提升。
在用作DRAM的模式下:
2.4.2.1 支持全系統(tǒng)掉電保護, 不少場景下為了防止異常掉電丟數(shù)據(jù)的commit and flush 的兩階段提交方法,可以省略成一階段的commit on write 的方法
2.4.2.2 為DRAM和SSD物理之間提供了一個新的存儲層
2.4.2.3 由于用作DRAM的時候,其訪問速度比SSD可能有1~3個數(shù)量級的提升,在一些文件系統(tǒng)中可以去掉對page cach的依賴,這樣反而更能控制上層業(yè)務的平均延時和服務穩(wěn)定性。
DAX:顧名思義,DAX就是Direct Access, bypass page cache。讀寫直接操作PMEM上的數(shù)據(jù),文件系統(tǒng)需要在mount 的時候,加入 "-o dax"參數(shù)。DAX極大地提高了文件系統(tǒng)在PMEM設備上的性能,但是還有一些問題沒有解決,比如:
文件系統(tǒng)的metadata還是需要使用page cache或buffer cache。
"-o dax" mount option是對整個文件系統(tǒng)的,不能做更細粒度的控制。
2.4.3 沒有一個API來告訴應用訪問的文件是不是可以DAX訪問的。
3、NVDIMM在Linux下的實現(xiàn)
持久內存是一種新型的計算機儲存,其速度接近動態(tài) RAM (DRAM),但同時具備 RAM 的按字節(jié)尋址能力以及固態(tài)硬盤 (SSD) 的性能;與傳統(tǒng)的 RAM 一樣,持久內存直接安裝在主板上的內存插槽中。因此,它的物理外形規(guī)格與 RAM 相同,以 DIMM 的形式提供。這些內存稱為 NVDIMM:非易失性雙列直插式內存模塊。
不過與 RAM 不同,持久內存在多個方面類似于基于閃存的 SSD。后兩者采用固態(tài)內存電路的形式,但除此之外,兩者都提供非易失性儲存:系統(tǒng)斷電或者重啟動后,內存中的內容會得到保留。使用這兩種媒體時,寫入數(shù)據(jù)的速度比讀取數(shù)據(jù)要慢;兩者都支持有限的重新寫入周期數(shù)。最后,與 SSD 一樣,如果在特定的應用方案中更適合對持久內存進行扇區(qū)級別的訪問,則也可以這樣做。
不同的型號使用不同形式的電子儲存媒體,例如 Intel 3D XPoint,或者將 NAND 閃存與 DRAM 結合使用。另外,行業(yè)正在開發(fā)新形式的非易失性 RAM。這意味著,不同的供應商和 NVDIMM 型號會提供不同的性能和持久性特征。
由于涉及的儲存技術處于早期開發(fā)階段,不同供應商的硬件可能會施加不同的限制。因此,以下敘述適用于一般性的場合。
持久內存的速度最多比 DRAM 要慢 10 倍,但比閃存要快大約 1000 倍。可在其中按字節(jié)重新寫入數(shù)據(jù),而不像在閃存中一樣,需要擦除整個扇區(qū),然后重新寫入數(shù)據(jù)。盡管重新寫入周期數(shù)有限,但大部分形式的持久內存可以應對數(shù)百萬次重新寫入,相比之下,閃存只能應對數(shù)千個周期。
這會產生兩種重要后果:使用最新的技術無法運行僅包含持久內存的系統(tǒng),因此無法實現(xiàn)完全非易失性的主內存,必須混合使用傳統(tǒng)的 RAM 和 NVDIMM。操作系統(tǒng)和應用程序將在傳統(tǒng)的 RAM 中執(zhí)行,而 NVDIMM 可提供極速的補充性儲存。
由于不同供應商的持久內存的性能特征不同,程序員可能需要考慮到特定服務器中 NVDIMM 的硬件規(guī)格,包括 NVDIMM 的數(shù)量,以及它們可以裝入到哪些內存插槽。顯然,這會對超級管理程序的使用、不同主機之間的軟件遷移等造成影響。
ACPI 標準版本 6 中定義了此新型儲存子系統(tǒng)。但是 libnvdimm 支持該標準頒布之前的 NVDIMM,可以相同的方式使用這些內存。
3.1、持久內存 (PMEM)
與 RAM 一樣,PMEM 儲存提供字節(jié)級別的訪問。使用 PMEM 時,單個名稱空間可以包含多個交錯式的 NVDIMM,使這些 NVDIMM 都可用作單個設備。可通過兩種方式來配置 PMEM 名稱空間。
將 PMEM 與 DAX 搭配使用
為 Direct Access (DAX) 配置 PMEM 名稱空間后,訪問內存時會繞過內核的頁面超速緩存,并直接進入媒體。軟件可以單獨直接讀取或寫入該名稱空間的每個字節(jié)。
將 PMEM 與 BTT 搭配使用
與在傳統(tǒng)的磁盤驅動器中一樣,將按扇區(qū)訪問配置為以 BTT 模式運行的 PMEM 名稱空間,而不是像在 RAM 中一樣采用按字節(jié)尋址的模式。某個轉換表機制會將訪問活動批處理成扇區(qū)大小的單元。
BTT 的優(yōu)點在于,儲存子系統(tǒng)會確保將每個扇區(qū)完全寫入到基礎媒體,如果某項寫入操作出于某種原因而失敗,則會取消注冊該操作。因此,無法在給定的扇區(qū)中進行部分寫入。此外,對 BTT 名稱空間的訪問會由內核超速緩存。缺點在于BTT 名稱空間不支持 DAX。
3.2、用于管理持久內存的工具
要管理持久內存,必須安裝 ndctl 包。安裝此包也會安裝 libndctl 包,后者提供一組用戶空間庫用于配置 NVDIMM。這些工具通過 libnvdimm 庫運行。該庫支持三種類型的 NVDIMM:
PMEM
BLK
同步 PMEM 和 BLK。
ndctl 實用程序提供一系列有用的手冊頁,可使用以下命令訪問這些:
ndctl help subcommand
要查看可用子命令的列表請使用:
ndctl --list-cmds
可用的子命令包括:
version:顯示 NVDIMM 支持工具的當前版本。
enable-namespace:使指定的名稱空間可供使用。
disable-namespace:阻止使用指定的名稱空間。
create-namespace:從指定的儲存設備創(chuàng)建新的名稱空間。
destroy-namespace:去除指定的名稱空間。
enable-region:使指定的區(qū)域可供使用。
disable-region:阻止使用指定的區(qū)域。
zero-labels:擦除設備中的元數(shù)據(jù)。
read-labels:檢索指定設備的元數(shù)據(jù)。
list:顯示可用的設備。
help:顯示有關工具用法的信息。
3.3、設置持久內存
3.3.1 查看可用的 NVDIMM 儲存
可以使用 ndctl list 命令列出系統(tǒng)中所有可用的 NVDIMM。在以下示例中,系統(tǒng)包含三個 NVDIMM,這些 NVDIMM 位于單個三通道交錯集內。
ndctl list --dimms [ { "dev":"nmem2", "id":"8089-00-0000-12325476" }, { "dev":"nmem1", "id":"8089-00-0000-11325476" }, { "dev":"nmem0", "id":"8089-00-0000-10325476" }]
如果結合不同的參數(shù),ndctl list 還可以列出可用的區(qū)域。
注意:區(qū)域可能不會按數(shù)字順序顯示。
請注意,盡管只有三個 NVDIMM,但它們卻顯示為四個區(qū)域。
ndctl list --regions [ { "dev":"region1", "size":68182605824, "available_size":68182605824, "type":"blk" }, { "dev":"region3", "size":202937204736, "available_size":202937204736, "type":"pmem", "iset_id":5903239628671731251 }, { "dev":"region0", "size":68182605824, "available_size":68182605824, "type":"blk" }, { "dev":"region2", "size":68182605824, "available_size":68182605824, "type":"blk" }
空間以兩種不同的形式顯示:三個 BLK 類型的獨立 64 GB 區(qū)域,或者一個 PMEM 類型的合并 189 GB 區(qū)域,后者將三個交錯式 NVDIMM 中的所有空間表示為單個卷。
請注意,available_size 的顯示值與 size 的顯示值相同。這意味著尚未分配任何空間。
3.3.2 將儲存配置為使用 DAX 的單個 PMEM 名稱空間
第一個示例將三個 NVDIMM 配置成使用 Direct Access (DAX) 的單個 PMEM 名稱空間。第一個步驟是創(chuàng)建新的名稱空間。
ndctl create-namespace --type=pmem --mode=fsdax --map=memory{ "dev":"namespace3.0", "mode":"memory", "size":199764213760, "uuid":"dc8ebb84-c564-4248-9e8d-e18543c39b69", "blockdev":"pmem3"}
這會創(chuàng)建支持 DAX 的塊設備 /dev/pmem3。設備名稱中的 3 繼承自父區(qū)域編號(在本例中為 region3)。
--map=memory 選項從 NVDIMM 中設置出一部分 PMEM 儲存空間,以便可以使用這些空間來分配稱作結構頁面的內部內核數(shù)據(jù)結構。這樣,便可以將新的 PMEM 名稱空間與 O_DIRECT I/O 和 RDMA 等功能搭配使用。
最終 PMEM 名稱空間的容量之所以小于父 PMEM 區(qū)域,是因為有一部分持久內存預留給了內核數(shù)據(jù)結構。
接下來,我們校驗新的塊設備是否可用于操作系統(tǒng):
fdisk -l /dev/pmem3Disk /dev/pmem3: 186 GiB, 199764213760 bytes, 390164480 sectorsUnits: sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 4096 bytesI/O size (minimum/optimal): 4096 bytes / 4096 bytes
與其他任何驅動器一樣,在使用該設備之前,必須先將其格式化。在本示例中,我們使用 XFS 將其格式化:
mkfs.xfs /dev/pmem3
...
接下來,可將新的驅動器裝入到某個目錄:
mount -o dax /dev/pmem3 /mnt/pmem3
然后,可以校驗是否獲得了一個支持 DAX 的設備:
mount | grep dax/dev/pmem3 on /mnt/pmem3 type xfs (rw,relatime,attr2,dax,inode64,noquota)
結果是,我們已獲得一個使用 XFS 文件系統(tǒng)格式化的,且裝有 DAX 的 PMEM 名稱空間。
對該文件系統(tǒng)中的文件進行任何 mmap() 調用都會返回直接映射到 NVDIMM 上的持久內存的虛擬地址,并且會完全繞過頁面超速緩存。對該文件系統(tǒng)中的文件進行任何 fsync 或 msync 調用仍可確保將修改后的數(shù)據(jù)完全寫入到 NVDIMM。這些調用會刷新通過 mmap 映射在用戶空間中修改的任何頁面的關聯(lián)處理器超速緩存行。
3.3.2.1 去除名稱空間
在創(chuàng)建使用相同儲存的其他任何類型的卷之前,我們必須卸載此 PMEM 卷,然后將其去除。
首先卸載該卷:
umount /mnt/pmem3
然后禁用名稱空間:
ndctl disable-namespace namespace3.0disabled 1 namespace
然后刪除該卷:
ndctl destroy-namespace namespace3.0destroyed 1 namespace
3.3.3 創(chuàng)建使用 BTT 的 PMEM 名稱空間
在下一個示例中,我們將創(chuàng)建使用 BTT 的 PMEM 名稱空間。
ndctl create-namespace --type=pmem --mode=sector{ "dev":"namespace3.0", "mode":"sector", "uuid":"51ab652d-7f20-44ea-b51d-5670454f8b9b", "sector_size":4096, "blockdev":"pmem3s"}
接下來,校驗新設備是否存在:
fdisk -l /dev/pmem3sDisk /dev/pmem3s: 188.8 GiB, 202738135040 bytes, 49496615 sectorsUnits: sectors of 1 * 4096 = 4096 bytesSector size (logical/physical): 4096 bytes / 4096 bytesI/O size (minimum/optimal): 4096 bytes / 4096 bytes
與前面配置的支持 DAX 的 PMEM 名稱空間一樣,這個支持 BTT 的 PMEM 名稱空間也會占用 NVDIMM 中的所有可用儲存。
注意:設備名稱 (/dev/pmem3s) 中的尾部 s 表示扇區(qū) (sector),可用于輕松辨別配置為使用 BTT 的名稱空間。
可按前一示例中所述格式化和裝入卷。
此處顯示的 PMEM 名稱空間不能使用 DAX,它會使用 BTT 來提供扇區(qū)寫入原子性。每次通過 PMEM 塊驅動程序進行扇區(qū)寫入時,BTT 都會分配一個新的扇區(qū)來接收新數(shù)據(jù)。完全寫入新數(shù)據(jù)后,BTT 將以原子方式更新其內部映射結構,使新寫入的數(shù)據(jù)可供應用程序使用。如果在此過程中的任意時間點發(fā)生電源故障,則寫入內容將會完全丟失,在這種情況下,應用程序可以訪問其舊數(shù)據(jù),而這些數(shù)據(jù)仍舊保持不變。這可以防止出現(xiàn)所謂"扇區(qū)撕裂"的情況。
與其他任何標準塊設備一樣,可以使用某個文件系統(tǒng)格式化這個支持 BTT 的 PMEM 名稱空間,并在該文件系統(tǒng)中使用它。無法將該名稱空間與 DAX 搭配使用。但是,此塊設備中的文件的 mmap 映射將使用頁面超速緩存。
3.4、使用內存(DRAM)模擬持久化內存(Persistent Memory)
3.4.1 精簡版:一般內核只需要兩步即可進行持久性內存模擬
1)配置 grub:
vim /etc/default/grub
在里面加入如下語句,前一個為要模擬的大小,后一個為模擬的持久性內存在內存中開始的位置。也就是從內存4G開始,劃分32G來模擬持久性內存。
GRUB_CMDLINE_LINUX="memmap=32G!4G"
2)更新 grub
update-grub && reboot
3.4.2 深入分析
現(xiàn)在真實的持久化內存對于普通用戶來說還不可用,在進行實驗和測試的時候可能需要模擬持久化內存來進行使用,現(xiàn)在在一臺主機上測試劃分一塊內存區(qū)域來進行持久化內存的模擬。
環(huán)境:Ubuntu 18.04,一臺普通的Dell臺式機,運行內存 8G。
從Linux 4.0以來,Linux內核就具備了對持久性內存設備和仿真的支持,但為了便于配置,建議使用比4.2更新的內核。在內核中,使用對文件系統(tǒng)的DAX擴展創(chuàng)建了一個支持PMEM的環(huán)境。某些發(fā)行版(如Fedora 24及更高版本)內置了DAX/PMEM支持。
要了解內核是否支持DAX和PMEM,可以使用以下命令:
# egrep '(DAX|PMEM)' /boot/config-`uname –r`
如果內置了支持就會輸出類似如下的內容:
CONFIG_X86_PMEM_LEGACY_DEVICE=y CONFIG_X86_PMEM_LEGACY=y CONFIG_BLK_DEV_RAM_DAX=y CONFIG_BLK_DEV_PMEM=m CONFIG_FS_DAX=y CONFIG_FS_DAX_PMD=y CONFIG_ARCH_HAS_PMEM_API=y
但是很遺憾,我們的Ubuntu 18.04沒有內置對DAX/PMEM的支持,所以輸入上述命令什么輸出都沒有。接下來就在Ubuntu 18.04上模擬持久化內存。由于在Ubuntu 18.04上默認沒有支持DAX和PMEM,所以需要我們重新編譯內核,并在編譯內核的配置選項中加入相關設置。
在這里重新編譯內核,選擇的版本是Linux-4.15。
首先輸入命令:
make nconfig
進入到如下的配置界面,配置PMEM和DAX
Device Drivers NVDIMM Support
配置PMEM
先進入到Device Drivers中,在Device Drivers中找到NVDIMM Support,需要將菜單欄向下翻,里面的內容并不只是我們看到的第一頁,NVDIMM Support 不在第一頁上。
進入到NVDIMM Support 中,將里面的內容都選中:
配置文件系統(tǒng)DAX
使用esc回到make nconfig的初始頁面
File System <*>Direct Access support
處理器特性設置
使用esc回到make nconfig的初始頁面
Processor type and features <*>Support non-standard NVDIMMs and ADR protected memory
其實上述所有過程,在Linux-4.15中默認都已經做了,也就是我只要 make nconfig就可以了。
所有這些配置好之后就開始編譯以及安裝內核:
# make -j9# make modules_install install
然后進入到新編譯的內核Linux-4.15中
使用下面的命令打印出e820表:
dmesg | grep e820
得到如下的內容:
[0.000000] e820: BIOS-provided physical RAM map: [0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009d7ff] usable [0.000000] BIOS-e820: [mem 0x000000000009d800-0x000000000009ffff] reserved...
上述的usable就是我們可以使用的,從中可以劃分部分區(qū)域來作為我們的持久化內存,在這里建議選取:
[0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000021f5fffff] usable
其中0x0000000100000000就是4G,需要配置grub來設置:
vim /etc/default/grub
我在里面直接配置4G的空間來模擬持久化內存,在grub中添加如下語句,表示空間大小為4G,從4G內存開始的內存空間用來模擬持久化內存:
GRUB_CMDLINE_LINUX="memmap=4G!4G"
配置好后,更新grub:update-grub
使用下面的命令查看是否成功:
dmesg | grep user
可以看到,這塊區(qū)域已經被模擬為了持久化內存,然后我們在主機 /dev目錄下可以看到pmem0的設備,至此就可以對模擬的持久化內存進行使用了。
使用方式--建立DAX文件系統(tǒng)
以ext4文件系統(tǒng)為例
mkdir /mnt/pmemdirmkfs.ext4 /dev/pmem0mount -o dax /dev/pmem0 /mnt/pmemdir
這樣就將目錄 /mnt/pmem掛載到了持久化內存上,這個目錄在之后的使用過程中就會用到。
參考來源:如何在英特爾 架構服務器上仿真持久性內存
3.4.3 使用memmap內核選項
pmem驅動程序允許用戶基于直接訪問文件系統(tǒng)(DAX)來使用EXT4和XFS。添加了一個新的memmap選項,該選項支持保留一個或多個范圍的未分配內存以用于模擬的持久內存。memmap參數(shù)文檔在Linux內核的相關頁面上。這個特性是在v4.0內核中向上擴展的。kernelv4.15引入了性能改進,推薦用于生產環(huán)境。
memmap選項使用memmap=nn[KMG]!ss[KMG]格式;其中nn是要保留的區(qū)域的大小,ss是起始偏移量,[KMG]指定大小(以千字節(jié)、兆字節(jié)或千兆字節(jié)為單位)。配置選項通過GRUB傳遞給內核,更改GRUB菜單項和內核參數(shù)在Linux發(fā)行版本之間有所不同,下面是一些常見Linux發(fā)行版的說明。有關更多信息,請參閱正在使用的Linux發(fā)行版和版本的文檔。
內存區(qū)域將標記為e820類型12(0xc),這在引導時可見,使用dmesg命令查看這些消息。
$ dmesg | grep e820
GRUB配置中的'memmap=4G!12G':保留4GB內存,從12GB到16GB。有關詳細信息,請參閱如何為系統(tǒng)選擇正確的memmap選項。每個Linux發(fā)行版都有不同的方法來修改GRUB配置,按照發(fā)行版的文檔進行操作即可,下面提供了一些常見的發(fā)行版以供快速參考。
1)、Ubuntu
$ sudo vim /etc/default/grubGRUB_CMDLINE_LINUX="memmap=4G!12G"
更新完成grub后重啟機器
$ sudo update-grub2
2)、RHEL
$ sudo vi /etc/default/grubGRUB_CMDLINE_LINUX="memmap=4G!12G"
正式開始更新grub配置
On BIOS-based machines:
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg
On UEFI-based machines:
$ sudo grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
可以使用多個配置,下面建立了兩個2G大小的名稱空間
"memmap=2G!12G memmap=2G!14G" will create two 2GB namespaces, one in the 12GB-14GB memory address offsets, the other at 14GB-16GB.
主機重新啟動后,應該存在一個新的/dev/pmem{N}設備,在GRUB配置中指定的每個memmap區(qū)域都有一個。這些可以使用ls/dev/pmem*顯示,命名約定從/dev/pmem0開始,并為每個設備遞增。/dev/pmem{N}設備可用于創(chuàng)建DAX文件系統(tǒng)。
使用/dev/pmem設備創(chuàng)建并裝載文件系統(tǒng),然后驗證是否為裝入點設置了dax標志,以確認啟用了dax功能。下面展示了如何創(chuàng)建和掛載EXT4或XFS文件系統(tǒng)。
1)、XFS
mkfs.xfs/dev/pmem0mkdir /pmem && mount -o dax /dev/pmem0 /pmemmount -v | grep /pmem/dev/pmem0 on /pmem type xfs (rw,relatime,seclabel,attr2,dax,inode64,noquota)
2)、EXT4
mkfs.ext4 /dev/pmem0mkdir /pmem && mount -o dax /dev/pmem0 /pmemmount -v | grep /pmem/dev/pmem0 on /pmem type ext4 (rw,relatime,seclabel,dax,data=ordered)
如何為系統(tǒng)選擇正確的memmap選項
為memmap內核參數(shù)選擇值時,必須考慮起始地址和結束地址代表可用的RAM。使用或與保留內存重疊可能導致?lián)p壞或未定義的行為,此信息可通過dmesg在e820表中輕松獲得。
下面的示例服務器具有16GiB內存,"可用"內存介于4GiB(0x100000000)和~16GiB(0x3ffffffff)之間:
$ dmesg | grep BIOS-e820[0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable[0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved[0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved[0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bffdffff] usable[0.000000] BIOS-e820: [mem 0x00000000bffe0000-0x00000000bfffffff] reserved[0.000000] BIOS-e820: [mem 0x00000000feffc000-0x00000000feffffff] reserved[0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved[0.000000] BIOS-e820: [mem 0x0000000100000000-0x00000003ffffffff] usable
要保留4GiB和16GiB之間的12GiB可用空間作為模擬持久內存,語法如下:
memmap=12G!4G
重新啟動后一個新的用戶定義的e820表項顯示范圍現(xiàn)在是"persistent(type12)":
$ dmesg | grep user:[0.000000] user: [mem 0x0000000000000000-0x000000000009fbff] usable[0.000000] user: [mem 0x000000000009fc00-0x000000000009ffff] reserved[0.000000] user: [mem 0x00000000000f0000-0x00000000000fffff] reserved[0.000000] user: [mem 0x0000000000100000-0x00000000bffdffff] usable[0.000000] user: [mem 0x00000000bffe0000-0x00000000bfffffff] reserved[0.000000] user: [mem 0x00000000feffc000-0x00000000feffffff] reserved[0.000000] user: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved[0.000000] user: [mem 0x0000000100000000-0x00000003ffffffff] persistent (type 12)
fdisk或lsblk程序可用于顯示容量,例如:
# fdisk -l /dev/pmem0Disk /dev/pmem0: 12 GiB, 12884901888 bytes, 25165824 sectorsUnits: sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 4096 bytesI/O size (minimum/optimal): 4096 bytes / 4096 bytes
# lsblk /dev/pmem0NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTpmem0 259:0 0 12G 0 disk /pmem
注意:大多數(shù)Linux發(fā)行版都啟用了內核地址空間布局隨機化(KASLR),這是由CONFIG_RANDOMIZE_BASE定義的。啟用后,內核可能會在沒有警告的情況下使用先前為持久內存保留的內存,從而導致?lián)p壞或未定義的行為,因此建議在16GiB或更低的系統(tǒng)上禁用KASLR。有關詳細信息,請參閱對應的Linux發(fā)行版文檔,因為每個發(fā)行版各不相同。
原文標題:萬字長文介紹Linux文件系統(tǒng)與持久性內存
文章出處:【微信公眾號:嵌入式ARM】歡迎添加關注!文章轉載請注明出處。
責任編輯:haq
-
內核
+關注
關注
3文章
1372瀏覽量
40277 -
存儲
+關注
關注
13文章
4296瀏覽量
85799 -
Linux
+關注
關注
87文章
11292瀏覽量
209328
原文標題:萬字長文介紹Linux文件系統(tǒng)與持久性內存
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論