本章では、 1 枚以上の NVDIMM から構成される不揮発性メインメモリ (永続型メモリ と呼ばれる場合もあります) を openSUSE Leap で使用するための情報を記述しています。
永続型メモリは新しいタイプのコンピュータストレージで、 DRAM (ダイナミック RAM) の高速性とバイト単位でのアクセス機能を維持したまま、ソリッドステートドライブ (SSD) の永続性を付加した仕組みを指します。
SUSE では現在、 AMD64/Intel 64 および POWER の各アーキテクチャで動作する openSUSE Leap で、永続型メモリの使用をサポートしています。
一般的な RAM と同様に、永続型メモリはメインボードのメモリスロットに直接差し込む形態で設置を行います。つまりこれは、 DIMM と呼ばれる通常型の RAM と物理的に全く同じ構造であることを意味しています。このような永続型メモリを NVDIMM (不揮発型 DIMM) と呼ぶ場合もあります。
ただし RAM とは異なり、永続型メモリは SSD のようなフラッシュメモリとも類似しています。 SSD も永続型メモリも半導体メモリではありますが、いずれも揮発性がありません。つまり、システムの電源を落としたり、再起動したりしても、中に書き込まれた内容はそのまま保持されるということを意味しています。またどちらの媒体も、書き込みのほうが読み込みよりも遅く、書き換え回数にも制限が存在しています。このほか SSD と同様に、永続型メモリはセクタ単位でのアクセスにも対応し、アプリケーション側からの要件に合わせることができるようになっています。
また、不揮発型メモリは Intel 3D XPoint という特殊なフラッシュメモリを搭載したものや、 NAND フラッシュと DRAM の両方を搭載したものなど、様々な構成で提供されています。このような新しい不揮発型メモリは現在も開発が続けられていて、様々な販売元がさらに性能を強化し耐久性を高めるよう新製品が作り続けられています。
このような永続型メモリの技術は未だ発展途上の段階にあるため、販売元によって様々な制限が存在する場合があります。そのため本章では、一般論のみを説明しています。
永続型メモリは DRAM と比べると 10 倍程度遅い仕組みですが、フラッシュメモリと比較すると 1000 倍程度高速です。フラッシュメモリは一般にセクタ単位で消去して書き換えを行いますが、永続型メモリは 1 バイト単位で書き換えが可能です。また、書き換え回数には制限があるものの、ほとんどの永続型メモリは 100 万回程度の書き換えに対応しています。これはフラッシュメモリの 1000 回程度に比べるとずっと大きな値です。
このようなことから、下記の 2 つの結果をもたらします:
現在の技術では、永続型メモリのみでシステムを動作させることはできないため、完全な永続性は提供できません。通常型の RAM と NVDIMM の両方を組み合わせて使用することになります。オペレーティングシステムやアプリケーションは通常型の RAM 内で実行し、 NVDIMM は高速な補助型ストレージとして使用することになります。
永続型メモリは販売元によって様々な性能の差異や特徴があることから、プログラマ側はサーバ内の NVDIMM のハードウエア特性を知っておく必要があります。これには NVDIMM の容量のほか、使用しているメモリスロットの場所も含まれます。これによってハイパーバイザ用途での使用やホストマシン間のソフトウエア移行など、様々な箇所の性能に影響があるためです。
この新しいストレージサブシステムは、 ACPI のバージョン 6 標準で規定されています。ただし、 libnvdimm
は標準化される前の NVDIMM のみに対応しているため、その仕組みでのみ使用できることに注意してください。
Intel Optane DIMM メモリは、下記の固有モードで使用することができます:
App Direct モード: Intel Optane メモリを高速な永続型ストレージとして使用するモードで、 SSD や NVMe デバイスの代替として扱うことができます。このモードを指定すると、システムの電源が落ちてもデータは保持されるようになります。
Memory モード: Intel Optane メモリを、 DRAM と比べて費用対効果の高い大容量メモリとして使用するモードです。このモードでは Optane DIMM の容量を生かして、個別の DIMM 内にアクセス頻度の高いデータをキャッシュとして保存します。ただし DRAM のみのシステムとは異なり、このモードはランダムアクセスの多い用途には向いておらず、性能が落ちてしまうことに注意してください。また、このモードを使用する場合は、アプリケーション側に Optane 固有の機能拡張を使用する必要があることにも注意してください。なお、このモードではシステムの電源が落とされると、データが失われます。
Mixed モード: Intel Optane メモリを内部で区分けして、上述の両方のモードを同時に使用します。
リージョン とは永続型メモリの中のブロックを意味する用語で、 1 つまたは複数の ネームスペース が含まれるものです。永続型メモリを使用する際には、まずネームスペースに割り当ててからアクセスを行います。
永続型メモリ内の連続したアドレス領域を指す用語で、 NVM Express SSD におけるネームスペースや SCSI での Logical Unit (LUN) と同じような意味を持ちます。ネームスペースはサーバ内の /dev
ディレクトリ内に個別のブロックデバイスとして提供されます。必要なアクセス方式によっても異なりますが、複数の NVDIMM からのストレージを組み合わせてネームスペースを大きなボリュームにしたり、小さなボリュームに分割したりすることもできます。
それぞれのネームスペースには モード が設定されます。これはネームスペース内で有効化する NVDIMM の機能を意味するもので、同じ親リージョンを持つ兄弟姉妹間のネームスペースでは同じ型になるものの、異なるモードを設定することができます。ネームスペースのモードには下記のようなものがあります:
デバイス DAX と呼ばれるモードで、単一のキャラクタデバイスファイル ( /dev/daxX.Y
) を作成します。このモードの場合、ファイルシステムの作成は不要です。
ファイルシステム DAX と呼ばれるモードで、何もモードを指定しない場合の既定値です。ext4
や XFS
のファイルシステムを構築できるブロックデバイス ( /dev/pmemX [.Y]
) を作成します。
チェックサムメタデータに対応していない古いファイルシステム向けの設定です。小さな起動ボリュームに最適な構成で、古いその他のオペレーティングシステムとの互換性もあります。
ラベルやメタデータを持たない純粋なメモリディスクのモードです。 DAX には対応していません。古いその他のオペレーティングシステムとの互換性があります。
raw
モードは SUSE ではサポート対象外となります。また、 raw
ネームスペース内に作成したファイルシステムをマウントすることもできません。
それぞれのネームスペースやリージョンには 型 が設定されます。この 型 はネームスペースやリージョンに割り当てられた永続型メモリへのアクセス方式を設定するもので、ネームスペースは親となるリージョンと同じ型になります。型には 2 種類のものがあり、それぞれ 永続型メモリ (さらに 2 種類の設定形態があります) と ブロックモード (古い形式です) と呼ばれています。
PMEM ストレージは通常のメモリ (RAM) と同様に、 1 バイト単位のアクセス機能を提供します。 PMEM を使用することで、複数のインターリーブされた NVDIMM を単一のネームスペースにまとめて 1 つのデバイスとして使用することができます。
PMEM 型のネームスペースの設定には、 2 種類の形態があります。
PMEM 型のネームスペースに対してダイレクトアクセス (DAX) を設定すると、メモリへのアクセス時にカーネルのページキャッシュを使用せず、直接メディアにアクセスするようになります。ソフトウエア側では、ネームスペース内の任意の箇所を個別に読み書きできるようになります。
PMEM 型のネームスペースに対して BTT モードを設定すると、通常のメモリアクセスのようなバイト単位でのアクセスではなく、通常のディスクドライブと同様のセクタ単位でのアクセスを行うようになります。変換テーブルの仕組みにより、セクタ単位で一括アクセスします。
BTT の利点はデータ保護にあります。ストレージサブシステムでは、それぞれのセクタがメディアに全て書き込まれたかどうかを監視しますので、書き込み切れていない場合 (たとえば何らかの理由で書き込みが失敗した場合など) はセクタ全体を以前の状態に戻す処理を行いますので、中途半端な状態にならないように動作します。
これに加えて、 BTT ネームスペースへのアクセスはカーネル側でのキャッシュ対象となります。
ただし、 BTT ネームスペースの場合は DAX を利用できない欠点があることに注意してください。
ブロックモードでは、それぞれの NVDIMM を個別のデバイスとして割り当てます。このモードは古い方式であり、サポート対象外となります。
devdax
以外の全ての型では、通常のドライブと同様にファイルシステムを指定してフォーマットを行う必要があります。 openSUSE Leap では ext2
, ext4
, XFS
の各ファイルシステムに対応しています。
DAX は永続型メモリに直接アクセスする方式で、 mmap
システムコールなどを利用してプロセスのアドレス領域内に直接マッピングすることができます。
特定の DIMM メモリ内のオフセット値として表現するメモリアドレスを意味します。 DIMM 内の最初のバイトを 0 とした値で表現します。
NVDIMM 内に保存されたメタデータで、たとえばネームスペースの設定などが含まれます。 DSM を利用してアクセスすることができます。
NVDIMM 内のファームウエアにアクセスするための ACPI メソッドです。
この形態でのメモリアクセスはトランザクション処理に対して 安全ではありません 。電源障害やその他のシステム障害が発生した場合、ストレージ内に全てのデータが書き込まれていることを保証できない仕組みであるため、アプリケーション側でそれを保証できる場合にのみ使用してください。
高速な巨大ストレージにバイト単位で直接アクセスできるアプリケーションを使用する場合は、プログラム側で mmap
システムコールを利用して永続型メモリをアプリケーションのメモリ領域に展開して使用することができます。この場合、追加のシステムメモリは不要となります。
ページキャッシュ用のメモリを節約したい場合は、カーネルのページキャッシュを使用しないように設定するものとし、余ったメモリはアプリケーション側に割り当てるようにしてください。たとえば永続型メモリを仮想マシン (VM) のイメージ保存用に占有させるような場合がそれに該当します。ページキャッシュを使用しないように設定することで、ホスト内でのメモリ使用量を削減できますので、それによってホスト内でさらに多くの VM を動作させることができるようになります。
こちらは永続型メモリを高速なディスクプールとして構成する場合に便利な仕組みです。たとえば BTT を指定した PMEM 内にファイルシステムのジャーナルを配置すると、電源やその他の障害が発生した場合に信頼性を向上させることができます (詳しくは 19.5.3項 「BTT を利用した PMEM ネームスペースの作成」 をお読みください) 。
アプリケーション側からは高速な SSD デバイスに見えますので、通常のストレージデバイスと同じように扱うことができます。たとえば永続型メモリ内に LVM を構成したりすることもできます。
また BTT はセクタ単位での書き込みを行いますので、常に一貫性が保たれる利点もあります。アプリケーション側ではデータの信頼性確保に力を注ぐことなく処理することができます。メディアエラーが発生したような場合でも、標準のエラー報告チャンネルを介して通知が行われます。
永続型メモリを管理するには、 ndctl
パッケージをインストールします。このパッケージをインストールすると libndctl
パッケージもインストールされますが、こちらは NVDIMM を設定するためのユーザスペース側ライブラリです。
これらのツールは libnvdimm
ライブラリを介して動作しますが、このライブラリは下記 3 種類の NVDIMM に対応しています:
PMEM
BLK
PMEM と BLK の共存環境
ndctl
にはさまざまなマニュアルページ (man
) が含まれています。マニュアルページを表示するには、下記のコマンドを実行してください:
>
ndctl help サブコマンド名
利用可能なサブコマンドの一覧を表示するには、下記のとおり実行してください:
>
ndctl --list-cmds
利用可能なサブコマンドには、下記のようなものがあります:
NVDIMM サポートツールのバージョンを表示します。
指定したネームスペースを使用できるように設定します。
指定したネームスペースを使用できないように設定します。
指定したストレージデバイスから新しいネームスペースを作成します。
指定したネームスペースを削除します。
指定したリージョンを使用できるように設定します。
指定したリージョンを使用できないように設定します。
デバイス内のメタデータを消去します。
指定したデバイスからメタデータを取得します。
利用可能なデバイスの一覧を表示します。
このツールの使用方法に関する情報を表示します。
ndctl
list
コマンドを実行すると、システム内で利用可能な全ての NVDIMM を表示することができます。
下記の例では、システム内に 3 つの NVDIMM が存在していて、それらは単一で 3 チャンネルのインターリーブセットを構成しています。
#
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
に異なるパラメータを指定することで、利用可能なリージョンの一覧を表示することもできます。
リージョンは番号順に出力されない場合があります。
下記は 3 つの NVDIMM が搭載されているものの、 4 つのリージョンが設定されていることに注意してください。
#
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" } ]
領域には 2 種類の異なる形式が設定されています。一方は 3 つの BLK 型の 64 GB の領域として、もう一方は 3 つの NVDIMM を単一のボリュームとして利用できる、 PMEM 型の 189 GB 領域です。
なお、上記の例では available_size
と size
の値が同じになっていますが、これは現時点では領域を何も使用していないことを表します。
最初の例では、 3 つの NVDIMM を単一の PMEM ネームスペースに統合し、これを直接アクセス (DAX) 型として設定します。
最初にやるべきことは、新しいネームスペースを作成することです。
#
ndctl create-namespace --type=pmem --mode=fsdax --map=memory
{ "dev":"namespace3.0", "mode":"memory", "size":199764213760, "uuid":"dc8ebb84-c564-4248-9e8d-e18543c39b69", "blockdev":"pmem3" }
上記を実行すると /dev/pmem3
という DAX に対応したブロックデバイスが作成されます。デバイス名の 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
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
次に、新しいドライブをディレクトリにマウントします:
#
mount -o dax /dev/pmem3 /mnt/pmem3
あとは DAX に対応したデバイスとしてマウントできていることを確認します:
#
mount | grep dax
/dev/pmem3 on /mnt/pmem3 type xfs (rw,relatime,attr2,dax,inode64,noquota)
上記までの作業で、 PMEM ネームスペースを XFS ファイルシステムでフォーマットし、 DAX でマウントすることができます。
このファイルシステム内のファイルに対して mmap()
システムコールを使用することで、 NVDIMM 内の永続型メモリに直接辿り着くことのできる仮想アドレスを取得することができます。もちろんページキャッシュは迂回する形になります。
このファイルシステム内のファイルに対して fsync
や msync
コールを実行すると、 NVDIMM 内に変更されたデータ全てを書き込んでいることが保証されます。これらのコールは、ユーザスペース側で mmap
した内容のページを、プロセッサキャッシュからも排除して書き込みを保証します。
同じストレージで別の種類のボリュームを作成したい場合は、あらかじめマウントを解除して PEM ストレージを削除しておく必要があります。
まずはマウントを解除します:
#
umount /mnt/pmem3
続いてネームスペースを無効化します:
#
ndctl disable-namespace namespace3.0
disabled 1 namespace
あとは削除するだけです:
#
ndctl destroy-namespace namespace3.0
destroyed 1 namespace
BTT はセクタ単位での書き込み一貫性を提供する仕組みで、 ext4 や xfs のジャーナルのようにデータ保護を必要とする場合に適切な選択肢です。電源障害が発生したりした場合、ジャーナルは保護され復元可能な状態にならなければなりませんが、下記の例では 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 は確保したセクタ内に書き込みが完了したことを確認したのち、内部マッピングを新しいセクタに書き換えて、アプリケーション側からアクセスできるようにします。この仕組みにより、処理中に電源障害が発生したような場合でも、書き込み前の古いデータを参照できるようになります。これにより、 「torn sectors」 と呼ばれる中途半端に書き込まれたデータになることを防いでいます。
このように BTT が有効化された PMEM ネームスペースは、通常の標準ブロックデバイスと同様にファイルシステムを指定してフォーマットすることができます。 DAX は使用できませんが、そのブロックデバイス内のファイルに対して mmap
を行うことでページキャッシュを使用することができます。
ファイルシステムのジャーナルを別のデバイスに配置する場合、元のファイルシステムと同じブロックサイズを使用しなければなりません。一般的には 4096 が最も使用されていますが、念のため下記のコマンドで確認してください:
#
blockdev --getbsz /dev/sda3
下記の例では、 NVDIMM デバイス内に新しい ext4 ジャーナルを、 SATA デバイス内に新しい ext4 ファイルシステムをそれぞれ作成して、ファイルシステムとジャーナルを結びつけるまでの処理を行っています:
#
mke2fs -b 4096 -O journal_dev /dev/pmem3s
#
mkfs.ext4 -J device=/dev/pmem3s /dev/sda3
下記の例では SATA ドライブに新しい XFS ファイルシステムを、別の NVDIMM デバイス内にジャーナルを作成しています:
#
mkfs.xfs -l logdev=/dev/pmem3s /dev/sda3
オプションの指定方法に関する詳細は、 man 8 mkfs.ext4
およびman 8 mkfs.ext4
をお読みください。
本件に関するその他の情報は、それぞれ下記をお読みください (いずれも英語のみの提供となります):
NVDIMM システムの設定手順やテストに関する情報、そして NVDIMM の有効化に関する個別の情報へのリンクがそれぞれ提供されています。このサイトは Linux 内での NVDIMM サポートとともに記述が進められています。
Linux やその他のオペレーティングシステムで、永続型メモリの設定方法やプログラミングシステムに関する情報が提供されています。ここにはユーザスペース側で永続型メモリを使用する際に便利な API を含む NVM ライブラリ (NVML) の説明もあります。
LIBNVDIMM: Non-Volatile Devices
カーネル開発者向けの資料で、最新の Linux カーネルツリー内の Documentation ディレクトリ以下にある文書です。 NVDIMM の有効化に関わるカーネルモジュールに関する説明のほか、カーネル内の実装に関する技術詳細や ndctl
ツールが使用する sysfs
カーネルインターフェイスに関する情報などが提供されています。
Linux カーネル内で libnvdimm
サブシステムを管理するためのユーティリティライブラリです。ユーザスペース側のライブラリのほか、単体テストやドキュメンテーションなども提供されています。