天天看點

Linux檔案系統與持久性記憶體介紹

點選上方 "程式設計技術圈"關注, 星标或置頂一起成長

Linux檔案系統與持久性記憶體介紹

背景回複“大禮包”有驚喜禮包!

每日英文

You must be strong now. You must never give up. And when you are afraid of the dark, don't forget the light is always there. 

你要堅強,決不能放棄。當你擔憂生活黑暗無邊之時,請記得希望總會在某處閃光。

每日掏心話

告訴自己:再苦再累,隻有堅持往前走。生活不會向你許諾什麼,尤其是不會向你許諾成功。

責編:樂樂 | 來自:阿炯

連結:freeoa.net/osuport/storagebak/linuxfs-nvdimm-intro_1898.html

程式設計技術圈(ID:study_tech)第 1139 次推文 圖源:百度

往日回顧:CTO 說了,如果發現誰用 kill -9 關閉程式就開除

   正文   

1、Linux 虛拟檔案系統介紹

在 Linux 系統中一切皆檔案,除了通常所說的狹義的檔案以外,目錄、裝置、套接字和管道等都是檔案。

檔案系統在不同的上下文中有不同的含義:

在儲存設備上組織檔案的方法,包括資料結構和通路方法,到儲存設備。

按照某種檔案系統類型格式化的一塊存儲媒體。我們常說在某個目錄下挂載或解除安裝檔案系統, 這裡的檔案系統就是這種意思。

核心中負責管理和存儲檔案的子產品,即檔案系統子產品。

Linux檔案系統的架構如下圖所示,分為使用者空間、核心空間和硬體3個層面:

Linux檔案系統與持久性記憶體介紹

注意:上圖中方塊對齊關系,很多時候我們分不清核心檔案系統中 "cache" 和 "buffer" 的差別,畢竟兩者都可以翻譯為 "緩存區",但是從圖中,就可以很清晰的看出所謂的 "cache" 其實指的就是圖中的 "頁緩存" 它是針對檔案來說的,除了 "DAX"(直接通路方式的裝置)它不使用 "緩存",其他的閃存類,塊裝置類裝置都會使用到 "頁緩存" 也就是 "cache",而 "buffer" 其實指的就是圖中的 "塊緩存" 它是針對塊裝置的。

Linux檔案系統與持久性記憶體介紹

1.1、硬體層面

外部儲存設備分為塊裝置、閃存和 NVDIMM 裝置 3 類,塊裝置主要有以下兩種:

機械硬碟:機械硬碟的讀寫機關是扇區。通路機械硬碟的時候,需要首先沿着半徑 方向移動磁頭尋找磁道,然後轉動盤片找到扇區。

閃存類塊裝置:使用閃存作為存儲媒體,裡面的控制器運作固化的驅動程式,驅動 程式的功能之一是閃存轉換層(Flash Translation Layer,FTL),把閃存轉換為塊裝置, 外表現為塊裝置。常見的閃存類塊裝置是在個人計算機和筆記本電腦上使用的固态硬碟 splid State Drives,SSD),以及在手機和平闆電腦上使用的嵌入式多媒體存儲卡(embedded Multi Media Card,eMMc)和通用閃存存儲(Universal Flash Storage,UFS)。閃存類塊裝置相對機械硬碟的優勢是:通路速度快,因為沒有機械操作:抗振性很高, 便于攜帶。

閃存(Flash Memory)的主要特點如下:

在寫入資料之前需要擦除一個擦除塊,因為向閃存寫資料隻能把一個位從 1 變成 0,不能從 0 變成 1,擦除的目的是把擦除塊的所有位設定為 1

一個擦除塊的最大擦除次數有限,NOR閃存的擦除塊的最大擦除次數是 10^4~10^3, NAND 閃存的擦除塊的最大擦除次數是 10^3~10^6。

閃存按存儲結構分為 NAND 閃存和 NOR 閃存,兩者的差別如下:

NOR閃存的容量小,NAND 閃存的容量大。

NOR 閃存支援按位元組尋址,支援晶片内執行(eXecute In Place,XIP),可以直接 在閃存内執行程式,不需要把程式讀到記憶體中; NAND 閃存的最小讀寫機關是頁或子頁, 一個擦除塊分為多個頁,有的 NAND 閃存把頁劃分為多個子頁。

NOR 閃存讀的速度比 NAND 閃存塊,寫的速度和擦除的速度都比 NAND 閃存慢

NOR 閃存沒有壞塊;NAND 閃存存在壞塊,主要是因為消除壞塊的成本太高 NOR 閃存适合存儲程式,一般用來存儲引導程式比如 uboot 程式;NAND 閃存适 合存儲資料。

為什麼要針對閃存專門設計檔案系統?主要原因如下:

NAND 閃存存在壞塊,軟體需要識别并且跳過壞塊。

需要實作損耗均衡( wear leveling),損耗均衡就是使所有擦除塊的擦除次數均衡, 避免一部分擦除塊先損壞。

機械硬碟和 NAND 閃存的主要差別如下:

機械硬碟的最小讀寫機關是扇區,扇區的大小一般是 512 位元組:NAND 閃存的最 小讀寫機關是頁或子頁。

機械硬碟可以直接寫入資料:NAND 閃存在寫入資料之前需要擦除一個擦除塊。

機械硬碟的使用壽命比 NAND 閃存長:機械硬碟的扇區的寫入次數沒有限制:NAND 閃存的擦除塊的擦除次數有限。

機械硬碟隐藏壞的扇區,軟體不需要處理壞的扇區:NAND 閃存的壞塊對軟體可 見,軟體需要處理壞塊。

NVDIMM(Nonn-Volatile DIMM,非易失性記憶體:DIMM 是 Dual-Inline-Memory-Modules 的縮寫,表示雙列直插式存儲子產品,是記憶體的一種規格)裝置把 NAND 閃存、記憶體和超級電容內建到一起,通路速度和記憶體一樣快,并且斷電以後資料不會丢失。在斷電的瞬間, 超級電容提供電力,把記憶體中的資料轉移到 NAND 閃存。

1.2、核心空間層面

在核心的目錄 fs 下可以看到,核心支援多種檔案系統類型。為了對使用者程式提供統一的 檔案操作接口,為了使不同的檔案系統實作能夠共存,核心實作了一個抽象層,稱為虛拟檔案系統(Virtual File System,VFS),也稱為虛拟檔案系統切換(Virtual Filesystem Switch,VFS) 檔案系統分為以下幾種。

塊裝置檔案系統,儲存設備是機械硬碟和固态硬碟等塊裝置,常用的塊裝置檔案 系統是 EXT 和 btrfs。EXT 檔案系統是 Linux 原創的檔案系統,目前有 3 個 成版本:EXT[2-4]。

閃存檔案系統,儲存設備是 NAND 閃存和 NOR 閃存,常用的閃存檔案系統是 JFFS2 ,(日志型閃存檔案系統版本2, Journalling Flash File System version2)和 UBIFS(無序區塊鏡像檔案系統, Unsorted Block Image File System)。記憶體檔案系統的檔案在記憶體中,斷電以後檔案丢失,常用的記憶體檔案系統是 tmpfs, 用來建立臨時檔案。

僞檔案系統,是假的檔案系統,隻是為了使用虛拟檔案系統的程式設計接口,常用的 僞檔案系統如下所示:

sockfs,這種檔案系統使得套接字(socket)可以使用讀檔案的接口 read 接收封包, 使用寫檔案的接口 write 發送封包。

proc 檔案系統,最初開發 proc 檔案系統的目的是把核心中的程序資訊導出到使用者空間, 後來擴充到把核心中的任何資訊導出到使用者空間,通常把 proc 檔案系統挂載在目錄 "proc" 下。

sysfs,用來把核心的裝置資訊導出到使用者空間,通常把 sysfs 檔案系統挂載在目錄 "/sys"下。

hugetlbfs,用來實作标準巨型頁。

cgroup 檔案系統,控制組(control group cgroup)用來控制一組程序的資源, cgroup 檔案系統使管理者可以使用寫檔案的方式配置 cgroup。

cgroup2 檔案系統, cgroup2 是 cgroup 的第二個版本, cgroup2 檔案系統使管理者可 以使用寫檔案的方式配置 cgroup2。

這些檔案系統又各自有着相關的特性:

頁緩存:通路外部儲存設備的速度很慢,為了避免每次讀寫檔案時通路外部儲存設備,檔案系統子產品為每個檔案在記憶體中建立了一個緩存,因為緩存的機關是頁,是以稱為頁緩存。

塊裝置層:塊裝置的通路機關是塊,塊大小是扇區大小的整數倍。核心為所有塊裝置實作了統一 的塊裝置層。

塊緩存:為了避免每次讀寫都需要通路塊裝置,核心實作了塊緩存,為每個塊裝置在記憶體中創 建一個塊緩存。緩存的機關是塊,塊緩存是基于頁緩存實作的。

IO 排程器:通路機械硬碟時,移動磁頭尋找磁道和扇區很耗時,如果把讀寫請求按照扇區号排序, 可以減少磁頭的移動,提高吞吐量。IO 排程器用來決定讀寫請求的送出順序,針對不同的 使用場景提供了多種排程算法:NOOP(No Operation)、CFQ(完全公平排隊, Complete Fair Queuing)和 deadline(限期)。NOOP 排程算法适合閃存類塊裝置,CFQ 和 deadline排程算 法适合機械硬碟。

塊裝置驅動程式:每種塊裝置需要實作自己的驅動程式。

核心把閃存稱為存儲技術裝置( Memory Technology Device,MTD),為所有閃存實作 了統一的 MTD 層,每種閃存需要實作自己的驅動程式。針對 NVDIMM 裝置,檔案系統需要實作 DAX(Direct Access直接通路:X 代表 eXciting,沒有意義,隻是為了讓名字看起來酷),繞過頁緩存和塊裝置層,把 NVDIMM 裝置裡面的記憶體直接映射到程序或核心的虛拟位址空間。

libnvdimm 子系統提供對 3 種 NVDIMM 裝置的支援:持久記憶體(persistent memory,PMEM) 模式的 NVDIMM 裝置,塊裝置(block,BLK)模式的 NVDIMM 裝置,以及同時支援PMEM 和 BLK 兩種通路模式的 NVDIMM 裝置。PMEM 通路模式是把 NVDIMM 裝置當作記憶體,BLK 通路模式是把 NVDIMM 裝置當作塊裝置。每種 NVDIMM 裝置需要實作自己的驅動程式。

2、下一代存儲技術NVIDMM

NVDIMM (Non-Volatile Dual In-line Memory Module) 是一種可以随機通路的, 非易失性記憶體。非易失性記憶體指的是即使在不通電的情況下, 資料也不會消失。是以可以在計算機掉電 (unexpected power loss), 系統崩潰和正常關機的情況下, 依然保持資料。NVDIMM 同時表明它使用的是 DIMM 封裝, 與标準DIMM 插槽相容, 并且通過标準的 DDR總線進行通信。考慮到它的非易失性, 并且相容傳統DRAM接口, 又被稱作Persistent Memory。

2.1、種類

目前, 根據 JEDEC 标準化組織的定義, 有三種NVDIMM 的實作。分别是:

NVDIMM-N

指在一個子產品上同時放入傳統 DRAM 和 flash 閃存,計算機可以直接通路傳統 DRAM。支援按位元組尋址,也支援塊尋址。通過使用一個小的後備電源,為在掉電時資料從 DRAM 拷貝到閃存中提供足夠的電能;當電力恢複時再重新加載到 DRAM 中。

Linux檔案系統與持久性記憶體介紹

NVDIMM-N示意圖

NVDIMM-N 的主要工作方式其實和傳統 DRAM是一樣的。是以它的延遲也在10的1次方納秒級。而且它的容量,受限于體積,相比傳統的 DRAM 也不會有什麼提升。

同時它的工作方式決定了它的 flash 部分是不可尋址的,而且同時使用兩種媒體的作法使成本急劇增加,但是 NVDIMM-N 為業界提供了持久性記憶體的新概念。目前市面上已經有很多基于NVIMM-N的産品。

NVDIMM-F

指使用了 DRAM 的DDR3或者 DDR4 總線的flash閃存。我們知道由 NAND flash 作為媒體的 SSD,一般使用SATA,SAS 或者PCIe 總線。使用 DDR 總線可以提高最大帶寬,一定程度上減少協定帶來的延遲和開銷,不過隻支援塊尋址。

NVDIMM-F 的主要工作方式本質上和SSD是一樣的,是以它的延遲在 10的1次方微秒級。它的容量也可以輕松達到 TB 以上。

NVDIMM-P

這是一個目前還沒有釋出的标準 (Under Development),預計将與 DDR5 标準一同釋出。按照計劃,DDR5将比DDR4提供雙倍的帶寬,并提高信道效率。這些改進,以及伺服器和用戶端平台的使用者友好界面,将在各種應用程式中支援高性能和改進的電源管理。

NVDIMM-P 實際上是真正 DRAM 和 flash 的混合。它既支援塊尋址, 也支援類似傳統 DRAM 的按位元組尋址。它既可以在容量上達到類似 NAND flash 的TB以上, 又能把延遲保持在10的2次方納秒級。

通過将資料媒體直接連接配接至記憶體總線,CPU 可以直接通路資料,無需任何驅動程式或 PCIe 開銷。而且由于記憶體通路是通過64 位元組的 cache line,CPU 隻需要通路它需要的資料,而不是像普通塊裝置那樣每次要按塊通路。

Intel 公司在2018年5月釋出了基于3D XPoint™ 技術的Intel® Optane™ DC Persistent Memory。可以認為是NVDIMM-P 的一種實作。

Linux檔案系統與持久性記憶體介紹

Intel® Optane™ DC Persistent Memory

2.2、硬體支援

應用程式可以直接通路NVDIMM-P, 就像對于傳統 DRAM那樣。這也消除了在傳統塊裝置和記憶體之間頁交換的需要。但是向持久性記憶體裡寫資料是和向普通DRAM裡寫資料共享計算機資源的。包括處理器緩沖區, L1/L2緩存等。

需要注意的是, 要使資料持久, 一定要保證資料寫入了持久性記憶體裝置, 或者寫入了帶有掉電保護的buffer。軟體如果要充分利用持久性記憶體的特性, 指令集架構上至少需要以下支援:

寫的原子性

表示對于持久性記憶體裡任意大小的寫都要保證是原子性的, 以防系統崩潰或者突然掉電。IA-32 和 IA-64 處理器保證了對緩存資料最大64位的資料通路 (對齊或者非對齊) 的寫原子性。是以, 軟體可以安全地在持久性記憶體上更新資料。這樣也帶來了性能上的提升, 因為消除了copy-on-write 或者 write-ahead-logging 這種保證寫原子性的開銷。

高效的緩存重新整理(flushing)

出于性能的考慮, 持久性記憶體的資料也要先放入處理器的緩存(cache)才能被通路。經過優化的緩存重新整理指令減少了由于重新整理 (CLFLUSH) 造成的性能影響。

a. CLFLUSHOPT 提供了更加高效的緩存重新整理指令

b. CLWB (Cache Line Write Back) 指令把cache line上改變的資料寫回記憶體 (類似CLFLUSHOPT),但是無需讓這條 cache line 轉變成無效狀态(invalid, MESI protocol),而是轉換成未改變的獨占狀态(Exclusive)。CLWB 指令實際上是在試圖減少由于某條cache line重新整理所造成的下次通路必然的cache miss。

送出至持久性記憶體(Committing to Persistence)

在現代計算機架構下,緩存重新整理的完成表明修改的資料已經被回寫至記憶體子系統的寫緩沖區。但是此時資料并不具有持久性。為了確定資料寫入持久性記憶體,軟體需要重新整理易失性的寫緩沖區或者在記憶體子系統的其他緩存。新的用于持久性寫的送出指令 PCOMMIT 可以把記憶體子系統寫隊列中的資料送出至持久性記憶體。

非暫時store操作的優化(Non-temporal Store Optimization)

當軟體需要拷貝大量資料從普通記憶體到持久性記憶體中時(或在持久性記憶體之間拷貝), 可以使用弱順序, 非暫時的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 的幾種實作方式,以及為了發揮NVDIMM-P 的性能所做的硬體上的優化和支援。下面會繼續介紹軟體方面的支援,包括程式設計模型、程式設計庫、SPDK方面的支援等。

在上篇的 NVDIMM介紹中,我們講解了NVDIMM幾種硬體上的實作方式,以及為了支援和優化性能所做的硬體上的改變。接下來讓我們來讨論一下為了充分發揮NVDIMM的性能,軟體方面做了哪些支援。有些人可能會有疑問, 為什麼用起來這麼麻煩?既然是持久性記憶體,不是應該關機什麼樣, 開機什麼樣, 就可以了嗎?其實目前來看, 這種想法還不會變為現實。因為除了DRAM是易失性的,比如 cache,寄存器這種也是易失性的。僅僅把記憶體做成持久性的也不能達成這樣的目的。另一個問題是, memory leak。如果發生了記憶體洩漏,重新開機一下就好了。那如果是持久性記憶體的洩漏呢?這也是一個很棘手的問題。Pmem有些方面類似于記憶體,也有些方面類似于存儲。但是,通常上我們不會認為Pmem能夠替代記憶體或存儲。其實,可以把它看作是一種補充,填補了記憶體和存儲之間巨大的差異。

在公衆号頂級架構師背景回複“架構整潔”,擷取一份驚喜禮包。

SPDK 在 17.10 中開始引入對于Pmem的支援。Pmem在SPDK的bdev層暴露為一個塊裝置,使用快裝置接口和上層進行通信。如下圖所示。

Linux檔案系統與持久性記憶體介紹

從圖中我們可以看到libpmemblk 把塊操作轉換成了位元組操作。它是怎麼做到的呢?在介紹libpmemblk 和 它背後的PMDK之前, 我們了解一下基礎知識。

mmap和DAX

首先,我們來看傳統的I/O方式, 即緩存I/O (Buffered I/O). 大多數作業系統預設的IO操作方式都是緩存IO。該機制使IO資料緩存在作業系統的page cache 中, 也就是說, 資料會被先拷貝到作業系統的核心空間的緩沖區中,然後才會從核心空間的緩沖區拷貝到指定的使用者位址空間。

Linux檔案系統與持久性記憶體介紹

在Linux 中, 這種通路檔案的方式就是通過read/write 系統調用來實作,如上圖。接下來, 我們比較一下記憶體映射IO mmap()。

接下來, 我們比較一下記憶體映射IO mmap()。

Linux檔案系統與持久性記憶體介紹

通過mmap獲得了對應檔案的一個指針,然後就像操作記憶體一樣進行指派或者做memcpy/strcpy. 這種我們稱之為load/store操作(這種操作一般需要msync、fsync來落盤)。

mmap因為建立了檔案到使用者空間的映射關系,可以看作是把檔案直接拷貝到使用者空間,減少了一次資料拷貝。但是mmap依然需要依靠page cache。

Linux檔案系統與持久性記憶體介紹

講完了mmap,那麼DAX是什麼呢?DAX即direct access,這個特性是基于mmap的。而DAX的差別在于完全不需要page cache,直接對儲存設備通路,是以它就是為了NVDIMM而生的。應用對于mmap的檔案操作,是直接同步到NVDIMM上的。DAX目前在XFS, EXT4, Windows的 NTFS 上都已經支援。需要注意的是, 使用這個模式,要對應用程式或者檔案系統進行修改。

Linux檔案系統與持久性記憶體介紹

2.3、NVM Programming Model

NVM Programming Model 大緻定義了三種使用方式。

2.3.1 最左邊Management 主要是通過driver提供的API對NVDIMM進行管理, 比如檢視容量資訊、健康狀态、固件版本、固件更新、模式配置等等。

2.3.2 中間, 作為存儲快裝置使用, 使用支援NVDIMM driver 的檔案系統和核心, 應用程式不用做任何修改,通過标準檔案接口通路NVDIMM。

2.3.3 第三種, 基于檔案系統的DAX特性,通過load/store操作,不需要page cache,同步落盤,沒有系統調用, 沒有中斷。這也是NVM Programming Model 的核心, 能夠充分釋放NVDIMM的性能優勢。但它的缺點在于,應用程式可能需要做一下改變。

PMDK

libpmemblk 實作了一個駐留在pmem中的同樣大小的塊的數組。裡面每個塊對于突然掉電,程式崩潰等情況依然保持原子事務性。libpmemblk是基于libpmem庫的,libpmem是PMDK中提供的一個更底層的庫, 尤其是對于flush的支援。它能夠追蹤每次對pmem的store操作,并保證資料落盤為持久性資料。

除此以外, PMDK 還提供了其他程式設計庫, 比如 libpmemobj,libpmemlog,libvmmalloc 等。感興趣可以通路其首頁擷取更多資訊。

結語

至此,對于NVDIMM硬體和軟體上的不同, 大家都有了一個大緻的認識。Intel 在2018年5月釋出了基于3D XPoint™ 技術的Intel® Optane™ DC Persistent Memory,引發了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的檔案系統

門為PMEM設計的檔案系統是NOVA Filesystem,感興趣的讀者可以參考NOVA的github。

ZUFS作為來自于NetApp的一個項目,ZUFS的全稱是Zero-copy User Filesystem。聲稱是實作了完全的zero-copy,甚至檔案系統的metadata都是zero-copy的。ZUFS主要是為了PMEM設計,但是也可以支援傳統的磁盤裝置,相當于是FUSE的zero-copy版本,是對FUSE的性能的提升。

在用作DRAM的模式下:

2.4.2.1 支援全系統掉電保護, 不少場景下為了防止異常掉電丢資料的commit and flush 的兩階段送出方法,可以省略成一階段的commit on write 的方法

2.4.2.2 為DRAM和SSD實體之間提供了一個新的存儲層

2.4.2.3 由于用作DRAM的時候,其通路速度比SSD可能有1~3個數量級的提升,在一些檔案系統中可以去掉對page cach的依賴,這樣反而更能控制上層業務的平均延時和服務穩定性。

DAX:顧名思義,DAX就是Direct Access, bypass page cache。讀寫直接操作PMEM上的資料,檔案系統需要在mount 的時候,加入 "-o dax"參數。DAX極大地提高了檔案系統在PMEM裝置上的性能,但是還有一些問題沒有解決,比如:

檔案系統的metadata還是需要使用page cache或buffer cache。

"-o dax" mount option是對整個檔案系統的,不能做更細粒度的控制。

2.4.3 沒有一個API來告訴應用通路的檔案是不是可以DAX通路的。

3、NVDIMM在Linux下的實作

持久記憶體是一種新型的計算機儲存,其速度接近動态 RAM (DRAM),但同時具備 RAM 的按位元組尋址能力以及固态硬碟 (SSD) 的性能;與傳統的 RAM 一樣,持久記憶體直接安裝在主機闆上的記憶體插槽中。是以,它的實體外形規格與 RAM 相同,以 DIMM 的形式提供。這些記憶體稱為 NVDIMM:非易失性雙列直插式記憶體子產品。

不過與 RAM 不同,持久記憶體在多個方面類似于基于閃存的 SSD。後兩者采用固态記憶體電路的形式,但除此之外,兩者都提供非易失性儲存:系統斷電或者重新開機動後,記憶體中的内容會得到保留。使用這兩種媒體時,寫入資料的速度比讀取資料要慢;兩者都支援有限的重新寫入周期數。最後,與 SSD 一樣,如果在特定的應用方案中更适合對持久記憶體進行扇區級别的通路,則也可以這樣做。

不同的型号使用不同形式的電子儲存媒體,例如 Intel 3D XPoint,或者将 NAND 閃存與 DRAM 結合使用。另外,行業正在開發新形式的非易失性 RAM。這意味着,不同的供應商和 NVDIMM 型号會提供不同的性能和持久性特征。

由于涉及的儲存技術處于早期開發階段,不同供應商的硬體可能會施加不同的限制。是以,以下叙述适用于一般性的場合。

持久記憶體的速度最多比 DRAM 要慢 10 倍,但比閃存要快大約 1000 倍。可在其中按位元組重新寫入資料,而不像在閃存中一樣,需要擦除整個扇區,然後重新寫入資料。盡管重新寫入周期數有限,但大部分形式的持久記憶體可以應對數百萬次重新寫入,相比之下,閃存隻能應對數千個周期。

這會産生兩種重要後果:使用最新的技術無法運作僅包含持久記憶體的系統,是以無法實作完全非易失性的主記憶體,必須混合使用傳統的 RAM 和 NVDIMM。作業系統和應用程式将在傳統的 RAM 中執行,而 NVDIMM 可提供極速的補充性儲存。

由于不同供應商的持久記憶體的性能特征不同,程式員可能需要考慮到特定伺服器中 NVDIMM 的硬體規格,包括 NVDIMM 的數量,以及它們可以裝入到哪些記憶體插槽。顯然,這會對超級管理程式的使用、不同主機之間的軟體遷移等造成影響。

ACPI 标準版本 6 中定義了此新型儲存子系統。但是 libnvdimm 支援該标準頒布之前的 NVDIMM,可以相同的方式使用這些記憶體。

3.1、持久記憶體 (PMEM)

與 RAM 一樣,PMEM 儲存提供位元組級别的通路。使用 PMEM 時,單個名稱空間可以包含多個交錯式的 NVDIMM,使這些 NVDIMM 都可用作單個裝置。可通過兩種方式來配置 PMEM 名稱空間。

将 PMEM 與 DAX 搭配使用

為 Direct Access (DAX) 配置 PMEM 名稱空間後,通路記憶體時會繞過核心的頁面超速緩存,并直接進入媒體。軟體可以單獨直接讀取或寫入該名稱空間的每個位元組。

将 PMEM 與 BTT 搭配使用

與在傳統的磁盤驅動器中一樣,将按扇區通路配置為以 BTT 模式運作的 PMEM 名稱空間,而不是像在 RAM 中一樣采用按位元組尋址的模式。某個轉換表機制會将通路活動批處理成扇區大小的單元。

BTT 的優點在于,儲存子系統會確定将每個扇區完全寫入到基礎媒體,如果某項寫入操作出于某種原因而失敗,則會取消注冊該操作。是以,無法在給定的扇區中進行部分寫入。此外,對 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:從指定的儲存裝置建立新的名稱空間。
  • destroy-namespace:去除指定的名稱空間。
  • enable-region:使指定的區域可供使用。
  • disable-region:阻止使用指定的區域。
  • zero-labels:擦除裝置中的中繼資料。
  • read-labels:檢索指定裝置的中繼資料。
  • list:顯示可用的裝置。
  • help:顯示有關工具用法的資訊。

3.3、設定持久記憶體

3.3.1 檢視可用的 NVDIMM 儲存

可以使用 ndctl list 指令列出系統中所有可用的 NVDIMM。在以下示例中,系統包含三個 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"
 }
]
           

如果結合不同的參數,ndctl list 還可以列出可用的區域。

注意:區域可能不會按數字順序顯示。

請注意,盡管隻有三個 NVDIMM,但它們卻顯示為四個區域。

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 區域,或者一個 PMEM 類型的合并 189 GB 區域,後者将三個交錯式 NVDIMM 中的所有空間表示為單個卷。

請注意,available_size 的顯示值與 size 的顯示值相同。這意味着尚未配置設定任何空間。

3.3.2 将儲存配置為使用 DAX 的單個 PMEM 名稱空間

第一個示例将三個 NVDIMM 配置成使用 Direct Access (DAX) 的單個 PMEM 名稱空間。第一個步驟是建立新的名稱空間。

ndctl create-namespace --type=pmem --mode=fsdax --map=memory
{
 "dev":"namespace3.0",
 "mode":"memory",
 "size":199764213760,
 "uuid":"dc8ebb84-c564-4248-9e8d-e18543c39b69",
 "blockdev":"pmem3"
}
           

這會建立支援 DAX 的塊裝置 /dev/pmem3。裝置名稱中的 3 繼承自父區域編号(在本例中為 region3)。

--map=memory 選項從 NVDIMM 中設定出一部分 PMEM 儲存空間,以便可以使用這些空間來配置設定稱作結構頁面的内部核心資料結構。這樣,便可以将新的 PMEM 名稱空間與 O_DIRECT I/O 和 RDMA 等功能搭配使用。

最終 PMEM 名稱空間的容量之是以小于父 PMEM 區域,是因為有一部分持久記憶體預留給了核心資料結構。

接下來,我們校驗新的塊裝置是否可用于作業系統:

fdisk -l /dev/pmem3
Disk /dev/pmem3: 186 GiB, 199764213760 bytes, 390164480 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/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 檔案系統格式化的,且裝有 DAX 的 PMEM 名稱空間。

在公衆号程式設計技術圈背景回複“Java”,擷取一份驚喜禮包。

對該檔案系統中的檔案進行任何 mmap() 調用都會傳回直接映射到 NVDIMM 上的持久記憶體的虛拟位址,并且會完全繞過頁面超速緩存。對該檔案系統中的檔案進行任何 fsync 或 msync 調用仍可確定将修改後的資料完全寫入到 NVDIMM。這些調用會重新整理通過 mmap 映射在使用者空間中修改的任何頁面的關聯處理器超速緩存行。

3.3.2.1 去除名稱空間

在建立使用相同儲存的其他任何類型的卷之前,我們必須解除安裝此 PMEM 卷,然後将其去除。

首先解除安裝該卷:

umount /mnt/pmem3
           

然後禁用名稱空間:

ndctl disable-namespace namespace3.0
disabled 1 namespace
           

然後删除該卷:

ndctl destroy-namespace namespace3.0
destroyed 1 namespace
           

3.3.3 建立使用 BTT 的 PMEM 名稱空間

在下一個示例中,我們将建立使用 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/pmem3s
Disk /dev/pmem3s: 188.8 GiB, 202738135040 bytes, 49496615 sectors
Units: sectors of 1 * 4096 = 4096 bytes
Sector size (logical/physical): 4096 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
           

與前面配置的支援 DAX 的 PMEM 名稱空間一樣,這個支援 BTT 的 PMEM 名稱空間也會占用 NVDIMM 中的所有可用儲存。

注意:裝置名稱 (/dev/pmem3s) 中的尾部 s 表示扇區 (sector),可用于輕松辨識配置為使用 BTT 的名稱空間。

可按前一示例中所述格式化和裝入卷。

此處顯示的 PMEM 名稱空間不能使用 DAX,它會使用 BTT 來提供扇區寫入原子性。每次通過 PMEM 塊驅動程式進行扇區寫入時,BTT 都會配置設定一個新的扇區來接收新資料。完全寫入新資料後,BTT 将以原子方式更新其内部映射結構,使新寫入的資料可供應用程式使用。如果在此過程中的任意時間點發生電源故障,則寫入内容将會完全丢失,在這種情況下,應用程式可以通路其舊資料,而這些資料仍舊保持不變。這可以防止出現所謂"扇區撕裂"的情況。

與其他任何标準塊裝置一樣,可以使用某個檔案系統格式化這個支援 BTT 的 PMEM 名稱空間,并在該檔案系統中使用它。無法将該名稱空間與 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 深入分析

現在真實的持久化記憶體對于普通使用者來說還不可用,在進行實驗和測試的時候可能需要模拟持久化記憶體來進行使用,現在在一台主機上測試劃分一塊記憶體區域來進行持久化記憶體的模拟。

環境:Ubuntu 18.04,一台普通的Dell桌上型電腦,運作記憶體 8G。

從Linux 4.0以來,Linux核心就具備了對持久性記憶體裝置和仿真的支援,但為了便于配置,建議使用比4.2更新的核心。在核心中,使用對檔案系統的DAX擴充建立了一個支援PMEM的環境。某些發行版(如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
        <M>PMEM;
        <M>BLK;
        <*>BTT
        <*>NVDIMM DAX
           

配置PMEM

先進入到Device Drivers中,在Device Drivers中找到NVDIMM Support,需要将菜單欄向下翻,裡面的内容并不隻是我們看到的第一頁,NVDIMM Support 不在第一頁上。

進入到NVDIMM Support 中,将裡面的内容都選中:

<M>PMEM;
    <M>BLK;
    <*>BTT
    <*>NVDIMM DAX
           

配置檔案系統DAX

使用esc回到make nconfig的初始頁面

File System
    <*>Direct Access support
           

處理器特性設定

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就是我們可以使用的,從中可以劃分部分區域來作為我們的持久化記憶體,在這裡建議選取:

[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
           

可以看到,這塊區域已經被模拟為了持久化記憶體,然後我們在主機 /dev目錄下可以看到pmem0的裝置,至此就可以對模拟的持久化記憶體進行使用了。

使用方式--建立DAX檔案系統

以ext4檔案系統為例

mkdir /mnt/pmemdir
mkfs.ext4 /dev/pmem0
mount -o dax /dev/pmem0 /mnt/pmemdir
           

 這樣就将目錄 /mnt/pmem挂載到了持久化記憶體上,這個目錄在之後的使用過程中就會用到。

參考來源:如何在英特爾® 架構伺服器上仿真持久性記憶體

3.4.3 使用memmap核心選項

pmem驅動程式允許使用者基于直接通路檔案系統(DAX)來使用EXT4和XFS。添加了一個新的memmap選項,該選項支援保留一個或多個範圍的未配置設定記憶體以用于模拟的持久記憶體。memmap參數文檔在Linux核心的相關頁面上。這個特性是在v4.0核心中向上擴充的。kernelv4.15引入了性能改進,推薦用于生産環境。

memmap選項使用memmap=nn[KMG]!ss[KMG]格式;其中nn是要保留的區域的大小,ss是起始偏移量,[KMG]指定大小(以千位元組、兆位元組或千兆位元組為機關)。配置選項通過GRUB傳遞給核心,更改GRUB菜單項和核心參數在Linux發行版本之間有所不同,下面是一些常見Linux發行版的說明。有關更多資訊,請參閱正在使用的Linux發行版和版本的文檔。

記憶體區域将标記為e820類型12(0xc),這在引導時可見,使用dmesg指令檢視這些消息。

$ dmesg | grep e820

GRUB配置中的'memmap=4G!12G':保留4GB記憶體,從12GB到16GB。有關詳細資訊,請參閱如何為系統選擇正确的memmap選項。每個Linux發行版都有不同的方法來修改GRUB配置,按照發行版的文檔進行操作即可,下面提供了一些常見的發行版以供快速參考。

1)、Ubuntu

$ sudo vim /etc/default/grub
GRUB_CMDLINE_LINUX="memmap=4G!12G"
           

更新完成grub後重新開機機器

$ sudo update-grub2
           

2)、RHEL

$ sudo vi /etc/default/grub
GRUB_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區域都有一個。這些可以使用ls/dev/pmem*顯示,命名約定從/dev/pmem0開始,并為每個裝置遞增。/dev/pmem{N}裝置可用于建立DAX檔案系統。

使用/dev/pmem裝置建立并裝載檔案系統,然後驗證是否為裝入點設定了dax标志,以确認啟用了dax功能。下面展示了如何建立和挂載EXT4或XFS檔案系統。

1)、XFS

mkfs.xfs /dev/pmem0
mkdir /pmem && mount -o dax /dev/pmem0 /pmem
mount -v | grep /pmem
/dev/pmem0 on /pmem type xfs (rw,relatime,seclabel,attr2,dax,inode64,noquota)
           

2)、EXT4

mkfs.ext4 /dev/pmem0
mkdir /pmem && mount -o dax /dev/pmem0 /pmem
mount -v | grep /pmem
/dev/pmem0 on /pmem type ext4 (rw,relatime,seclabel,dax,data=ordered)
           

如何為系統選擇正确的memmap選項

為memmap核心參數選擇值時,必須考慮起始位址和結束位址代表可用的RAM。使用或與保留記憶體重疊可能導緻損壞或未定義的行為,此資訊可通過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表項顯示範圍現在是"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/pmem0
Disk /dev/pmem0: 12 GiB,  12884901888 bytes, 25165824 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
           
# lsblk /dev/pmem0
NAME  MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
pmem0 259:0    0  12G  0 disk /pmem
           

注意:大多數Linux發行版都啟用了核心位址空間布局随機化(KASLR),這是由CONFIG_RANDOMIZE_BASE定義的。啟用後,核心可能會在沒有警告的情況下使用先前為持久記憶體保留的記憶體,進而導緻損壞或未定義的行為,是以建議在16GiB或更低的系統上禁用KASLR。有關詳細資訊,請參閱對應的Linux發行版文檔,因為每個發行版各不相同。

4、參考來源

Linux虛拟檔案系統介紹

28.持久記憶體

Persistent Memory Documentation

下一代存儲技術的先行: NVDIMM 你了解嗎(上)

下一代存儲技術的先行: NVDIMM 你了解嗎(下)

PS:歡迎在留言區留下你的觀點,一起讨論提高。如果今天的文章讓你有新的啟發,歡迎轉發分享給更多人。

版權申明:内容來源網絡,版權歸原創者所有。除非無法确認,我們都會标明作者及出處,如有侵權煩請告知,我們會立即删除并表示歉意。謝謝!

歡迎加入後端架構師交流群,在背景回複“學習”即可。

Linux檔案系統與持久性記憶體介紹

猜你還想看

阿裡、騰訊、百度、華為、京東最新面試題彙集

有人靠"搶茅台"月入百萬,腳本曝光,開源可用!網友:太強了~

死磕18個Java8日期處理,工作必用!

告赢了!程式員拒絕春節帶電腦回家工作被開除,判決獲賠19.4萬!

BAT等大廠Java面試經驗總結

Linux檔案系統與持久性記憶體介紹

繼續閱讀