24 持續性記憶體 #
本章包含關於使用裝備非揮發性主記憶體之 SUSE Linux Enterprise Server 的額外資訊。此類記憶體稱做持續性記憶體,由一或多個 NVDIMM 構成。
24.1 簡介 #
持續性記憶體是一種新型機器儲存,其速度接近普通的動態 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,這些記憶體的使用方式相同。
24.2 詞彙 #
- 區域
區域是持續性記憶體中可劃分為一或多個名稱空間的區塊。如果不事先將某個區域配置到名稱空間,則您無法存取該區域的持續性記憶體。
- 名稱空間
非揮發性儲存的單個連續定址範圍,相當於 NVM Express SSD 的名稱空間,或 SCSI 邏輯單位 (LUN)。名稱空間做為獨立區塊裝置顯示在伺服器的
/dev
目錄中。根據所需的存取方法,名稱空間可將多個 NVDIMM 中的儲存合併成較大磁碟區,或者允許將這些儲存分割成較小的磁碟區。- 模式
每個名稱空間都有相應的模式,用於定義要為該名稱空間啟用的 NVDIMM 功能。同一父區域的旁支名稱空間一律具有相同的類型,但可將其設定為使用不同的模式。名稱空間模式包括:
- raw
一個記憶體磁碟。不支援 DAX。與其他作業系統相容。
- 磁區
適用於不執行中繼資料檢查總數計算的傳統檔案系統。適用於小型開機磁碟區。與其他作業系統相容。
- fsdax
檔案系統 DAX 模式。如果未指定其他模式,則使用預設值。建立區塊裝置 (
/dev/pmemX [.Y]
),支援將 DAX 用於ext4
或XFS
。- devdax
裝置 DAX 模式。建立單字元裝置檔案 (
/dev/daxX.Y
). 不需要建立檔案系統。
- 類型
每個名稱空間和區域都有一種類型,該類型定義如何存取與該名稱空間或區域關聯的持續性記憶體。名稱空間的類型永遠與其父區域的類型相同。類型分為以下兩種:持續性記憶體和區塊模式。
- 持續性記憶體 (PMEM)
與 RAM 一樣,PMEM 儲存提供位元組層級的存取。這會啟用直接存取 (DAX),表示存取記憶體時會繞過核心的頁面快取,直接進入到媒體中。此外,使用 PMEM 時,單個名稱空間可以包含多個交錯式 NVDIMM,因而這些 NVDIMM 都可做為單個裝置供系統存取。
- 區塊模式 (BLK)
BLK 存取發生在磁區 (通常為 512 位元組) 中,透過定義的存取視窗 aperture 進行。此行為更像是傳統的磁碟機。也就是說,讀取和寫入都是由核心進行快取。使用 BLK 存取模式時,每個 NVDIMM 可做為一個獨立的名稱空間供系統存取。
有些裝置支援 PMEM 和 BLK 兩種模式。此外,有些裝置允許將儲存區分割成多個獨立的名稱空間,以便能夠使用 PMEM 存取其中一些名稱空間,並使用 BLK 存取另一些名稱空間。
除了
devdax
名稱空間外,必須將所有其他類型格式化為ext2
、ext4
或XFS
等檔案系統,就像對傳統的磁碟機進行格式化一樣。- Direct Access (DAX)
DAX 允許將持續性記憶體直接對應成程序的位址空間 (例如,使用
mmap
系統呼叫進行對應)。此功能適合用於在在未使用任何額外 RAM 的情況下直接存取大量 PMEM、註冊多個適用於 RDMA 的 PMEM 區塊,或者直接將其指定給虛擬機器。- DIMM 實體位址 (DPA)
在單個 DIMM 的記憶體中用做偏移量的記憶體位址;也就是說,在該 DIMM 中用做最低可定址位元組的從零開始的位址。
- 標籤
儲存在 NVDIMM 中的中繼資料,例如名稱空間定義。可以使用 DSM 存取這些資料。
- 裝置特定的方法 (DSM)
用於存取 NVDIMM 中韌體的 ACPI 方法。
24.3 使用案例 #
24.3.1 將 PMEM 與 DAX 搭配使用 #
必須注意,這種記憶體存取方式不是交易性的。如果發生斷電或其他系統故障,資料可能不會完全寫入儲存。僅當應用程式可以處理部分寫入資料的情況時,PMEM 儲存才適用。
24.3.1.1 可受益於較大位元組可定址儲存容量的應用程式。 #
如果伺服器代管的某個應用程式可逐位元組直接使用較大的快速儲存容量,則程式設計師可以使用 mmap
系統呼叫,將持續性記憶體區塊直接放入該應用程式的位址空間,而無需使用任何額外的系統 RAM。
24.3.1.2 避免使用核心頁面快取 #
您可以節省用於頁面快取的 RAM,而不要將 RAM 配置給應用程式。例如,可以專門使用非揮發性記憶體來儲存虛擬機器 (VM) 影像。由於這些影像不會快取,因此可以減少主機上的快取使用量,從而可在每部主機上設定更多的 VM。
24.3.2 將 PMEM 與 BTT 搭配使用 #
當您想要使用一組 NVDIMM 中的持續性記憶體做為類似磁碟的極速儲存池時,此方法非常有用。
對於應用程式而言,此類裝置僅顯示為極速 SSD,並可像其他任何儲存裝置一樣供您使用。例如,LVM 可以排布在非揮發性儲存的頂層,如往常一樣正常運作。
BTT 的優點在於可以保證磁區寫入的不可部分完成性,因此,即使是依存於資料完整性的複雜應用程式也能保持正常運作。可透過標準的錯誤報告通道來執行媒體錯誤報告。
24.3.3 BLK 儲存 #
儘管它擁有更強大的功能,可以防範單一裝置故障,但需要進行額外的管理,因為每個 NVDIMM 都顯示為一個獨立的裝置。因此,一般慣用帶有 BTT 的 PMEM。
在更新版本的 SUSE Linux Enterprise Server 中將取代並不再支援 BLK 儲存。
24.4 用於管理持續性記憶體的工具 #
若要管理持續性記憶體,必須安裝 ndctl
套件。安裝此套件也會安裝 libndctl
套件,後者提供一組使用者空間庫來設定 NVDIMM。
這些工具透過 libnvdimm
庫運行。該庫支援三種類型的 NVDIMM:
PMEM
BLK
同步 PMEM 和 BLK。
ndctl
公用程式提供一系列有用的 man
頁面。可使用以下指令存取這些頁面:
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
顯示關於工具用法的資訊。
24.5 設定持續性記憶體 #
24.5.1 檢視可用的 NVDIMM 儲存 #
可以使用 ndctl
list
指令列出系統中所有可用的 NVDIMM。
在以下範例中,系統包含三個 NVDIMM,它們位於單個三通道交錯集內。
root #
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,但它們卻顯示為四個區域。
root #
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
的顯示值相同。這意味著尚未配置任何空間。
24.5.2 將儲存設定為使用 DAX 的單個 PMEM 名稱空間 #
第一個範例將三個 NVDIMM 設定為使用 Direct Access (DAX) 的單個 PMEM 名稱空間。
第一個步驟是建立新的名稱空間。
root #
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 區域,是因為有一部分持續性記憶體保留給了核心資料結構。
接下來,我們驗證新的區塊裝置是否可用於作業系統:
root #
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 將其格式化:
root #
mkfs.xfs /dev/pmem3
meta-data=/dev/pmem3 isize=256 agcount=4, agsize=12192640 blks = sectsz=4096 attr=2, projid32bit=1 = crc=0 finobt=0, sparse=0 data = bsize=4096 blocks=48770560, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal log bsize=4096 blocks=23813, version=2 = sectsz=4096 sunit=1 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0
接下來,可將新的磁碟機掛接到某個目錄:
root #
mount -o dax /dev/pmem3 /mnt/pmem3
然後,可以驗證是否得到了一個支援 DAX 的裝置:
root #
mount | grep dax
/dev/pmem3 on /mnt/pmem3 type xfs (rw,relatime,attr2,dax,inode64,noquota)
結果是,我們已得到一個使用 XFS 檔案系統格式化的,且掛接有 DAX 的 PMEM 名稱空間。
對該檔案系統中的檔案進行任何 mmap()
呼叫,都會傳回直接對應至 NVDIMM 上的持續性記憶體的虛擬位址,並且會完全繞過頁面快取。
對該檔案系統中的檔案進行任何 fsync
或 msync
呼叫仍可確定將修改後的資料完全寫入 NVDIMM。這些呼叫會衝洗透過 mmap
對應在使用者空間中修改之任何頁面的關聯處理器快取行。
24.5.2.1 移除名稱空間 #
在建立使用相同儲存的其他任何磁碟區類型之前,我們必須卸載此 PMEM 磁碟區,然後將其移除。
首先卸載該磁碟區:
root #
umount /mnt/pmem3
然後停用名稱空間。
root #
ndctl disable-namespace namespace3.0
disabled 1 namespace
然後刪除該磁碟區:
root #
ndctl destroy-namespace namespace3.0
destroyed 1 namespace
24.5.3 建立使用 BTT 的 PMEM 名稱空間 #
在下一個範例中,我們將建立使用 BTT 的 PMEM 名稱空間。
root #
ndctl create-namespace --type=pmem --mode=sector
{ "dev":"namespace3.0", "mode":"sector", "uuid":"51ab652d-7f20-44ea-b51d-5670454f8b9b", "sector_size":4096, "blockdev":"pmem3s" }
接下來,驗證新裝置是否存在:
root #
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
表示磁區,可用於輕鬆辨別設定為使用 BTT 的 PMEM 和 BLK 名稱空間。
可依前一範例中所述格式化和掛接磁碟區。
這裡顯示的 PMEM 名稱空間不能使用 DAX。它會使用 BTT 來提供磁區寫入不可部分完成性。每次透過 PMEM 區塊驅動程式進行磁區寫入時,BTT 都會配置一個新的磁區來接收新資料。完全寫入新資料後,BTT 將以不可部分完成性的方式更新其內部對應結構,使新寫入的資料可供應用程式使用。如果在此過程中的任意時點發生電源故障,則寫入內容將會完全遺失,在這種情況下,應用程式可以存取其舊資料,而這些資料仍舊保持不變。如此可以防止出現所謂「磁區撕裂」的情況。
與其他任何標準區塊裝置一樣,可以使用某種檔案系統格式化這個支援 BTT 的 PMEM 名稱空間,並在該檔案系統中使用它。無法將該名稱空間與 DAX 搭配使用。但是,此區塊裝置中檔案的 mmap
對應會使用頁面快取。
在上面兩個範例中,所有 NVDIMM 提供的空間都合併到一個磁碟區中。如同非備援磁碟陣列一般,這表示如果任何個別 NVDIMM 發生錯誤,整個磁碟區的內容都可能會遺失。磁碟區中包含的 NVDIMM 越多,發生類似錯誤的機率就越高。
24.5.3.1 移除 PMEM 磁碟區 #
如上例所述,在重新配置空間之前,必須先移除磁碟區和名稱空間:
root #
ndctl disable-namespace namespace3.0
disabled 1 namespaceroot #
ndctl destroy-namespace namespace3.0
destroyed 1 namespace
24.5.4 建立 BLK 名稱空間 #
在此範例中,我們將建立三個獨立的 BLK 裝置:每個 NVDIMM 各建立一個。
這種方法的優勢之一是,如果任何個別 NVDIMM 發生故障,其他磁碟區將不會受到影響。
必須針對每個名稱空間重複以下指令:
root #
ndctl create-namespace --type=blk --mode=sector
{ "dev":"namespace1.0", "mode":"sector", "uuid":"fed466bd-90f6-460b-ac81-ad1f08716602", "sector_size":4096, "blockdev":"ndblk1.0s" }root #
ndctl create-namespace --type=blk --mode=sector { "dev":"namespace0.0", "mode":"sector", "uuid":"12a29b6f-b951-4d08-8dbc-8dea1a2bb32d", "sector_size":4096, "blockdev":"ndblk0.0s" }root #
ndctl create-namespace --type=blk --mode=sector
{ "dev":"namespace2.0", "mode":"sector", "uuid":"7c84dab5-cc08-452a-b18d-53e430bf8833", "sector_size":4096, "blockdev":"ndblk2.0s" }
然後,我們可以驗證新裝置是否存在:
root #
fdisk -l /dev/ndblk*
Disk /dev/ndblk0.0s: 63.4 GiB, 68115001344 bytes, 16629639 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
Disk /dev/ndblk1.0s: 63.4 GiB, 68115001344 bytes, 16629639 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
Disk /dev/ndblk2.0s: 63.4 GiB, 68115001344 bytes, 16629639 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
針對 BLK 名稱空間產生的區塊裝置命名為 /dev/ndblkX.Y
,其中 X 為父區域編號,Y 為該區域內唯一的名稱空間編號。因此,/dev/ndblk2.0s
為區域 2 的子名稱空間編號 0。
如上例所述,尾端的 s
表示該名稱空間設定為使用 BTT,也就是說,它用於基於磁區的存取。由於它們是透過區塊視窗
進行存取的,程式無法使用 DAX,但會對存取進行快取。
與以往一樣,必須將這些裝置格式化並掛接後才能使用。
24.6 疑難排解 #
持續性記憶體的耐用性優於 SSD 儲存,但也可能會用完。如果某個 NVDIMM 發生故障,就需要隔離出現問題的個別模組,以便能夠復原剩餘資料並更換硬體。必須確定以下三條資訊:
發生故障的是哪個 NVDIMM 模組:已損壞模組的實體位置。
現在包含已損壞區塊的是哪個名稱空間 (
/dev/pmemX
)。還有其他哪些名稱空間或區域也在使用該實體模組。
確定已損壞模組以及使用該模組的所有名稱空間和區域之後,便可以備份其他未受影響的名稱空間中的資料,然後關閉伺服器並更換 NVDIMM。
24.6.1 尋找故障模組 #
伺服器主機板上的 DIMM 插槽中有一組 NVDIMM。
在產生的空間中,作業系統會建立一或多個名稱空間,例如 region0
。
在這些區域內定義了某些名稱空間,例如 /dev/pmem1
或 /dev/dax0
。
例如,假設有一個區域由來自三個 NVDIMM 的空間構成,該區域已設定為以下三個名稱空間:
NVDIMM 0 |
region0 |
/dev/pmem1 | |
NVDIMM 1 |
[X] |
/dev/pmem2s | |
NVDIMM 2 |
/dev/dax0 |
在我們的範例中,標記為 [X] 的 region0
部分已損壞。
您必須:
確定包含受影響區域的 NVDIMM 模組。
如果該區域跨多個 NVDIMM 交錯,此步驟尤為重要。
備份受影響 NVDIMM 上任何其他名稱空間的內容。
在此範例中,必須備份
/dev/pmem2s
的內容。確定名稱空間與 NVDIMM 實體位置 (位於主機板的哪個記憶體插槽中) 之間的關係。
必須關閉伺服器並取下外蓋,找到、移除並更換已損壞模組。
24.6.2 測試持續性記憶體 #
要進行測試,需要有 nfit_test
核心模組。
ndctl
指令所對應 GitHub 頁面中的單位測試
部分的步驟 1 - 4 中詳細介紹了測試程序。請參閱本章結尾處的第 24.7 節 「更多資訊」。
執行帶有參數
list -RM
的ndctl
指令。此操作將顯示已損壞區塊的清單。
tux >
sudo
ndctl list -RM : : { "dev":"region5", "size":33554432, "available_size":33554432, "type":"pmem", "iset_id":4676476994879183020, "badblock_count":8, "badblocks":[ { "offset":32768, "length":8, "dimms":[ "nmem1" 1 ] } ] }, :此處識別了這個特定的 NVDIMM。
執行帶有參數
list -Du
的ndctl
指令。此操作將顯示 DIMM 的處理器。
tux >
sudo
ndctl list -Du { "dev":"nmem1", "id":"cdab-0a-07e0-feffffff", "handle":"0x1", 1 "phys_id":"0x1" }, : :這是 NVDIMM 的處理器。
執行帶有參數
list --d DIMM name
的ndctl
指令。tux >
sudo
ndctl list -R -d nmem1 [ { "dev":"region5", "size":33554432, "available_size":33554432, "type":"pmem", "iset_id":4676476994879183020, "badblock_count":8 }, : :
24.7 更多資訊 #
以下清單中提供了更多關於此主題的資訊︰
包含關於設定 NVDIMM 系統的指示、關於測試的資訊,以及關於啟用 NVDIMM 的規格連結。隨著 Linux 中 NVDIMM 支援功能的不斷發展,此網站的內容也會不斷擴充。
關於在 Linux 和其他作業系統中設定、使用非揮發性記憶體,以及對使用此類記憶體的系統進行程式設計的資訊。其中介紹了 NVM 庫 (NVML)。該庫提供有用的 API 用於在使用者空間中進行持續性記憶體程式設計。
此文件面向核心開發人員,包含在目前 Linux 核心樹狀結構的「文件」資料夾中。其中探討了涉及啟用 NVDIMM 的不同核心模組,列出了關於核心實作的一些技術詳細資料,並介紹了
ndctl
工具使用的sysfs
核心介面。用於管理 Linux 核心中
libnvdimm
子系統的公用程式庫。此外還包含使用者空間庫,以及單元測試和文件。