お伝えしたいこと
Fedora33以降では、ディスク上に割り当てたswap領域 (swapパーティション、swapファイル) をほぼ使わなくなりました。
代わりにzramと呼ばれるメモリ上の領域を使います。
もちろん、仕組み上ディスクを利用したswapよりもzramの方が従来よりもメモリ消費量は少し上がります。
しかし、zramに入るデータは圧縮される上、メモリなのでI/O性能が良くなることが期待されています。
メモリ容量の少ない環境においては、この圧縮機構によって寧ろメモリ容量を節約できてしまいます。
そんなzramを使ったswapの画期的な実装について、今回は簡単に触れたいと思います (※)。
(※) ちなみにWikipedia - zramによれば、zram自体は2014/3/30にLinux kernel 3.14でzramは安定していると判断され、メインラインにリリースされています。実は結構歴史がある技術なんですね
Fedora32以前の挙動
概要
恐らく、今動作している大半のLinuxのデフォルトに該当する挙動です。
swap領域はディスク上に作成します。
作成方法は、以下の流れです。
- swap専用のパーティション、またはファイルを用意する
- swap用にフォーマットする
- OS起動時にswap領域を自動認識させる
- swap領域を有効化する
RHEL8の公式手順1を参考にしつつ、コマンド例を簡単に示します。
既に知っているという方は、#Fedora33以降の挙動までスキップしてください。
swap用のパーティション、またはファイルを用意する
swapファイルを使う場合は、dd
コマンドでファイルを作成しておきます。
以下のコマンドでは1KiBのブロックを1048576 (1024*1024) 個生成し、1GiBのswapfileを生成しています。
sudo dd if=/dev/zero of=/swapfile bs=1024 count=1048576 sudo chmod 600 /swapfile
swapパーティションを作る場合は、fdiskなどでパーティションを作っておきます。
パーティションの作成方法については、ここでは割愛します。
必要に応じて、過去の記事を参考にしてください。
ここでは、/dev/vda6
パーティションを作成し、swap用に割り当てたとします。
swap用にフォーマットする
mkswap
コマンドにファイルパス、またはデバイスファイルを指定してフォーマットします。
sudo mkswap /swapfile
# または、sudo mkswap /dev/vda6 (swapパーティションの場合)
OS起動時にswap領域を自動認識させる
/etc/fstab
に以下の行を追加します。
/swapfile swap swap defaults 0 0 # または、/dev/vda6 swap swap defaults 0 0 (swapパーティションの場合)
/etc/fstab
を編集したら、systemdが変更を認識できるように以下のコマンドを実行し、各unitに設定ファイルを再読込させます。
sudo systemctl daemon-reload
swap領域を有効化する
swapon
コマンドでswap領域をその場で有効化します。
OS再起動は不要です。
sudo swapon /swapfile
# または、sudo swapon /dev/vda6 (swapパーティションの場合)
確認
swapon --show
でswap領域が認識されたことを確認できます。
free
でも、swap領域が増えたことを確認できます。
swapon --show # NAME TYPE SIZE USED PRIO # /swapfile partition 1G 0B -2 free -h # total used free shared buff/cache available # Mem: 62Gi 17Gi 14Gi 1.3Gi 30Gi 43Gi # Swap: 1.0Gi 0B 1.0Gi
Fedora33以降の挙動
概要
Fedora33では、デフォルト設定でzramと呼ばれる領域がメモリ上に作成され、swap領域として使用されます。
実はswap領域にはpriorityというパラメータがあり、複数のswap領域が存在する場合にはpriorityが高い領域から優先的に使用されます。
デフォルトでは、以下のpriority値になっていました。
swapの作成場所 | priority値 |
---|---|
zram | 100 |
ディスク (swap file, swap partition) |
-2 |
つまり、Fedora33以降では、ディスク上のswap領域は基本的に使われません。
zram上のswap領域が枯渇した場合のみ、ディスク上のswap領域が使われ始めます。
滅多にないと思いますが、priorityが同じデバイスが複数あった場合にはラウンドロビンになります。
※この挙動は、man 2 swapon
に書いてあります
swapのpriorityは、zramについてはzram-generator.confで (#後述)、ディスクについては/etc/fstab
やswapon
のオプションで指定可能です。
ディスクのpriorityのデフォルト値は、man mkswap
によると本来-1
のはずです。
ただ、実機を見ると-2
になっていたので、実質的にzram以外のswapはデフォルトで最小のpriorityになります。
-2
に制御しているところがどこにあるかまではわかりませんでした。
zramによるswap作成を無効化してFedora32以前の動作に戻すことも可能ですが、メリットもあるので不具合等なければそのまま使うのが良いでしょう。
以下のセクションで、仕様の詳細に触れていきたいと思います。
段々深くなっていきますが、#zramとは、#zramの特徴はオススメです。
Fedoraを初めとするRed Hat系のディストリビューションをお使いの方は是非目を通してください。
なお、本記事ではFedoraのmanやリリースノートを主な情報源としています。
Linux Kernelのレイヤーでの深い解説については、後述の#参考記事にわかりやすい記事がありますので、そちらを参考にしてください。
zramとは
zramとはRAM上に動的に生成されたブロックデバイスです。
zram上に格納されるデータは全て圧縮され、対応する無圧縮のメモリ使用量と比較して、zramにswap outされた時のデータサイズは小さくなります。
「RAM上にブロックデバイスを動的に生成する」といえばRAM Diskというものもありますが、zramの場合はデータを圧縮するため、容量効率が良くなります。
デバイスファイルは、/dev/zramN
(Nは0以上の整数)で、Fedoraでは/dev/zram0
がデフォルトで作成されています。
Linux Kernelには、zswapという似たような技術もありますが、zramとは別物です。2, 3
zramの特徴
zram視点でメリット/デメリットを列挙します。
- | 詳細 |
---|---|
○ | Disk I/Oが少なくなる。 swap outを伴うI/O処理が高速化される。 Flashデバイス (SSDなど) を使用している場合も、繰り返しの書き込みに伴う故障/性能劣化 (wearing out) を軽減する効果がある |
○ | RAM容量を効率的に活用できる。 zramも結局のところRAM上にswapをするので、RAM容量を消費する。 しかし、データ圧縮によってswap outされた領域が約1/2程度のサイズになるので、メモリが少ない環境において十分に役に立つ (参考) |
△ | データ退避の効率が50%程度 (目安)。 1つ上の行の言い換えになる。 データ圧縮効率が50%ということは、サイズ100のデータをswap outすることで、サイズ50のメモリ容量を消費するということ。 ディスク退避する場合は、サイズ100のデータをswap outした場合のメモリ消費量は0。 この点も考慮して、zramのswap sizeはディスクの場合と比べて2倍程度で検討するのが良いという考え方もありそう (えんでぃ主観) |
△ | 圧縮処理に多少のリソースを使う。 メモリのオーバーヘッドは0.1%程度 (1GiBのswapあたり、メタデータなどにより1MiBを追加で消費) です。 CPUにも負荷がかかります。 従って、CPU/メモリの負荷を考慮すると、zramのサイズを極端に大きくすべきではありません (参考) |
× | 圧縮効率の悪いデータとは相性が悪い。 効率の悪いデータを頑張って圧縮しても、CPU時間を浪費するだけになってしまう...可能性がある (参考)。 しかし、Fedora33で試したところ実際は圧縮効率が悪いケースは観測されなかったという報告もあり、Fedora34以降はよりzramを積極活用するようチューニングされた (参考) |
まとめると、全体的にメリットが大きいですが以下の点には注意が必要です。
- ディスクに退避する場合と比較してRAM消費量が大きくなる
- CPU使用率が上がる
逆に、主観ですがCPU、メモリ共に余裕のある設計であれば、あまり気にしなくても良いと思います。
zramの設定ファイル
zramのデフォルトの挙動は、/usr/lib/systemd/zram-generator.conf
に記載があります。
このファイルを直接編集することは推奨されていません。
編集方法については、次の#zram-generator.confの設定変更にて触れます。
Fedora34以降のファイルの中身は、以下のようになっています。
[zram0] zram-fraction = 1.0 max-zram-size = 8192
ちなみに、Fedora33時点では以下の設定内容でした。
/dev/zram0
を作成し、後はデフォルト値を使用していました。
[zram0]
[zramN]
(Nは0以上の整数)の配下にパラメータを設定することが可能です。
man zram-generator.confによると、デフォルト値は以下のようになっています。
※Fedora33では、man 5 zram-generator
で確認できます
※手元のFedora35で使っているカーネルバージョンは、5.14.16-301.fc35.x86_64
です
※swapと関係ないパラメータはいくつか省略しています
パラメータ名 | 詳細 |
---|---|
host-memory-limit | zramに割り当て可能な仮想メモリ容量 (物理メモリ容量 + swapメモリ容量) の上限を指定する。/proc/meminfo 相当の情報で、詳細はman proc を参照。単位はMB。 この上限を超えると、zramデバイスはそもそも生成しなくなる。 デフォルト値は none のため、制限なし |
zram-fraction | zramデバイスのサイズを決定する係数 (比例定数) を指定する。 0以上の小数が入る。 デフォルト値は0.5。 例えばホストのRAMサイズが8GiBで、zram-fraction=0.5の場合、zramサイズは4GiBとなる。 zram-fraction=1.0の場合、ホストのRAMサイズと同等のzramサイズになる。 実際のzramサイズは、この上でmax-zram-sizeの影響も受けて最終的に決定される |
max-zram-size | zram-fractionで得られたzramサイズの上限値を指定する。 単位はMB。 noneを指定すると上限無しになる。 デフォルト値は4096 |
compression-algorithm | 圧縮処理のアルゴリズムを指定する。 デフォルト値はカーネルによって決まる。 ※Fedora35では lzo-rle でした他に指定可能なアルゴリズムは、 /sys/block/zram0/comp_algorithm から読み取れる。※Fedora35では、 lzo lzo-rle lz4 lz4hc 842 zstd でした |
swap-priority | swapのpriority値を指定する。 -1〜32667の間で指定可能。 デフォルト値は100。 ※ /etc/fstab でswapのpriorityを指定していない場合は、ディスクベースのswapは負のpriority値を持ちます。従って、デフォルトの挙動ではディスクよりもzramのswapが優先的に使用されます |
なお、本セクションで述べた「zramデバイスのサイズ」とは、圧縮前のサイズです (#後述のzramctlのDISKSIZE相当)。
実際に消費されるRAMサイズ (zramctlのCOMPRやTOTAL相当) は、zramデバイスのサイズよりも小さくなります。
Fedora34以降で採用されたzram-fraction = 1.0
という設定は確かにアグレッシブではありますが、実際にzramctlで圧縮効率を計測して1/2や1/3であったことから、ある程度勝算を持ってのパラメータ設計となっています4。
まとめると、zram-generator.conf
のデフォルト設定 (=Fedora33のデフォルト) では以下のような動作になります。
※zramのサイズはRAMサイズの0.5倍。ただし、4GiBが上限
zram device size [MB] ^ │ 4G>│ ooooooooooooo │ o │ o │ o 2G>│ o │ o │ o 512M>│ o 0───────────────────────> total usable RAM [MB] ^ ^ ^ 1G 4G 8G
Fedora35のデフォルト設定はzram-fraction=1.0
, max-zram-size=8192
のため、以下のようなグラフになります。
zram device size [MB] ^ │ 8G>│ ooooooooooooo │ o │ o │ o 4G>│ o │ o │ o 1G>│ o 0───────────────────────> total usable RAM [MB] ^ ^ ^ 1G 4G 8G
zram-generator.confの設定変更
本セクションの情報は、man zram-generator.confに基づいています。
設定ファイルの配置場所は、これだけあるようです。
- /usr/lib/systemd/zram-generator.conf
- /usr/local/lib/systemd/zram-generator.conf
- /etc/systemd/zram-generator.conf
/run/systemd/zram-generator.conf
/usr/lib/systemd/zram-generator.conf.d/*.conf
- /usr/local/lib/systemd/zram-generator.conf.d/*.conf
- /etc/systemd/zram-generator.conf.d/*.conf
- /run/systemd/zram-generator.conf.d/*.conf
デフォルト設定は、/usr/lib/systemd/zram-generator.conf
にあります。
その後、パッケージインストールなどによって設定ファイルが追加配置される場合は、/usr/local/lib/systemd/zram-generator.conf.d/*.conf
にファイルが追加されていきます。
*.conf
*.conf
のファイルは文字列ソート順に読み込まれます。
後から読み込まれた設定値が先に読み込んだ設定値を上書きします。
手動で設定変更する場合は、/etc/systemd/zram-generator.conf
と/etc/systemd/zram-generator.conf.d/*.conf
に記載します。
/etc
配下にファイルを配置すると、/usr/lib
配下のファイルが読み込まれなくなります。
従って、既存設定が必要な場合はそちらも忘れずに書く必要があります。
裏を返せば、sudo touch /etc/systemd/zram-generator.conf
で空のファイルを生成すれば、デフォルトの/dev/zram0
を作成するという挙動がなくなります。
つまり、zramによるswap動作を無効化できます5。
実際にファイルを生成し、OS再起動したら反映できました。
zram、swapの状態確認
zramctl
やswapon --show
でswapの状態を確認できます。
zramctl
: swapに関わらず全てのサイズが0以上のzramデバイスを表示swapon --show
: zramに関わらず全てのswap領域を表示
手元のFedora35で実行したログを掲載します。
zramctl # NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT # /dev/zram0 lzo-rle 8G 4K 74B 12K 8 [SWAP] zramctl --output-all # NAME DISKSIZE DATA COMPR ALGORITHM STREAMS ZERO-PAGES TOTAL MEM-LIMIT MEM-USED MIGRATED MOUNTPOINT # /dev/zram0 8G 4K 74B lzo-rle 8 0 12K 0B 12K 0B [SWAP] swapon --show # NAME TYPE SIZE USED PRIO # /swapfile file 2G 0B -2 # /dev/zram0 partition 8G 0B 100
zramctlの出力について補足します。
zramctl --help
から確認できます6。
項目が多いですが、実用上はNAME, DISKSIZE, DATA, TOTALあたりを見れば十分だと思います。
zramctl --output-all
を使うことは基本ありません。
列名 | 今回の値 | 意味 |
---|---|---|
NAME | /dev/zram0 | zramデバイス名 |
DISKSIZE | 8G | zramに格納可能なデータサイズの上限 (未圧縮換算) |
DATA | 4K | zramに実際に格納されているデータサイズ (未圧縮換算) |
COMPR | 74B | zramに実際に格納されているデータサイズ (圧縮済換算) |
ALGORITHM | lzo-rle | 圧縮に使用しているアルゴリズム |
STREAMS | 8 | 圧縮処理の同時並列実行数 |
ZERO-PAGES | 0 | page frameと紐付いていないswap page数 (※) |
TOTAL | 12K | COMPR (実データ) に、メモリフラグメンテーションやメタデータなどのオーバーヘッドを加えた正味のデータサイズ (圧縮済換算) |
MEM-LIMIT | 0B | データ格納に使えるメモリ容量の上限 (圧縮済換算) ※ zram-generator.conf のhost-memory-limit など変えてみましたが、この値とは関係ありませんでした |
MEM-USED | 12L | zramが圧縮データを格納するために使用しているメモリサイズ ※TOTALとの違いがいまいちわかりません |
MIGRATED | 0B | memory compactionによって移動されたメモリのサイズ1 |
MOUNTPOINT | [SWAP] | zramデバイスがマウントされている場所 (※2) |
(※1)
swap pageとは、swap領域上のvirtual pageのことだと理解しています。
page frameとは、物理メモリ上の最小アドレス単位です。
virtual pageとは、仮想メモリ上の最小アドレス単位で、OSが認識するメモリアドレス単位でもあります。7,
仮想メモリとは、OSが認識している抽象化されたメモリで、物理的に複数枚に分かれたメモリやswapなどを単一のアドレスで管理するものです8。
memory pageについてより深く知りたい方は、Wikipedia - Memory pagingもチェックしてみてください
(※2)
zramそのものはブロックデバイスを生成する仕組みで、swapだけに使われるとは限りません
今回はzramctlコマンドを参照目的で使いましたが、このコマンドによりzramの動作を動的に変更することも可能です。
参考記事
この記事よりも先に、@shimauma_Zzzzzさんがzramについて深く解説されていました。
Linux Kernelのドキュメントまで踏み込んで、低レイヤーから仕様を解説してくださっています。
/proc
周りの値の意味や、echo
で書き換えた時の挙動まで解説されていて、zram-generator
の内部処理をより具体的にイメージできました。
この記事を書くに先立ち、私も大いに勉強させていただきました。
ありがとうございます。
(参考) swap領域の一般論
参考情報として、swapに関する雑多な情報をこちらに書きます。
参考元URLなどは特にありません。
カジュアルなまとめとして見てください。
swap領域とは、基本的にメモリ容量が足りなくなった時にメモリ上のデータが退避される領域です。
ファイルシステムによってはキャッシュに使われることもあるようで、メモリが枯渇していなくても少量使われることがあると聞いたことがあります。
多くの構成では、swap領域はディスク上に作成されるため、メモリと比較してI/Oが遅いです。
特にハードディスクを使っている環境において、メモリ不足に起因するswap退避が大量に発生すると性能劣化が顕著になると言われています。
性能観点でのswap領域に関する議論は、様々なブログや掲示板で展開されています。
例えば...
- 今どきのメモリ容量は十分に大きいので、swap領域を作る必要はない (過去に口頭で言われたことがあります)
- RHELについては、RAMサイズの半分のswap領域を作成することが推奨。メモリ8GiB以上の場合は、4GiBのswap領域が一つの目安9
- swappinessを変更することで、swap発生頻度を調整する主張もある (全ての主張は、ブログや掲示板など非公式のものです)
- swappinessをデフォルトの60よりも小さく、1〜3にすべきという意見がある (根拠は怪しい)
- 変えるべきではないとの意見もある
- zramを使う場合は最大の100でも良いという意見もある
- swappinessの挙動の理解は非常に難しい。親切なドキュメントはない。ソースコードを追えたとしても難しい
- swappinessの挙動は、過去に大幅に変わったことがある。今ある解説記事も最新とは限らない
このような形で、意見を総合して明確な結論を出すことは難しいです。
明確な根拠はありませんが、私は以下の方針としました。
- swappinessはいじらない
- swap領域のサイズは、RHELの推奨に従う (検証サーバの場合は1GiBなどにすることも多い)
Fedora33以降の場合はzramに任せておけば自動的に上記の構成になるので、楽で良いですね。
時代が進むに連れて仕組みが整備されているので、理由がなければ標準に乗るのが一番です。
まとめ
Fedora34、Fedora35で大幅に挙動が変わったzram, swap周りについて紹介しました。
RHEL9も同様の設計になった場合、swapfileやswap partitionを作るのはやめようかな...と思い始めています。
今後の動きが楽しみですね。
-
LWN.net - Memory compaction ※memory compactionとは、メモリページ間でデータを移動することでフラグメンテーションを減らす処理のこと↩
-
Fedora Wiki - Changes/SwapOnZRAM - #How can it be disabled? ※
sudo systemctl stop swap-create@zram0
は、Fedora33ではコマンドが通りましたが、Fedora35では通りませんでした↩ -
Wikipedia - Page (computer memory) ※physical page = page frame. page = virtual page = memory page.↩
-
Red Hat - RHEL8 - Managing storage devices - #12.2. Recommended system swap space↩