近年のPCやシングルボードコンピュータは、マルチコア、複数個のCPUで構成されています。Raspberry Pi 4 Model Bの場合、コア数は4個のようです。
たとえばソースコードのコンパイル時、マルチコアを有効利用するために、複数のジョブを作成して、複数のプロセスを同時に実行する場合があります。make -j 5はジョブ5個の意味になります。
そのような場合、プロセスが増えてメインメモリーが不足し、マシンの動作が不安定になる場合があります。現実問題、メモリー容量2GBではコンパイルが進まない場合もあります。
その回避のため、swapファイルを作成し、暇なプロセスの一時的な退避先を作る必要がありますが。ストレージを使用するため、速度は遅く、microSDカードやSSDの寿命に影響します。
そこで。swap領域を、ファイルやパーティションではなく、メインメモリー上に圧縮して作ることが可能です。イメージ的にはRAMディスクにswapを作り、さらに圧縮する感じです。
Raspberry Pi OSにて、そのようなzramを使用する覚書を記録したいと思います。
Raspberry Pi OSのzram作成手順の覚書
使用するOSは64ビット版Raspberry Pi OS bullseye
本体は、Raspberry Pi 4 Model B メモリー4GB版を使用しました。
zramはメインメモリー上に作成し、さらに圧縮して使用しますので、メモリー容量が多いほうが効果的かと思います。
OSは、64ビット版のRaspberry Pi OS Liteを使用しました。Liteではなく通常版も問題無いと思います。
対応するDebianのバージョンは11(bullseye)になります。
zramの容量はMiB,GiBで指定
zramの作り方によっては、割合、メインメモリーの容量に対する、パーセントで作成できる場合もありますが。
今回は、Raspberry Pi OS付属のzramctlコマンドで作成しようと思います。
このため、容量はMiB, GiB、メビバイト、ギビバイト等で指定する必要があります。
MB,GBは、10の◯乗、MiB,GiBは2の◯乗になります。少し容量が小さめに表示されるほうが、GiB,MiBでしょうか。
ファイルキャッシュを取るかzramを取るか
Linuxでは、プロセスに使用していないメモリー、空きメモリー容量は、ファイルのキャッシュに使用されています。topコマンドのbuff/cache欄になります。
zramとして使用する場合は、ファイルのキャッシュが減り、その分、プロセス空間に使用できる容量が増える、つまり起動できるプログラムの数が増える、ということになります。
問題は、どのくらいの容量をzramに使用するかですが。
ここでは、メインメモリーの6割を基準にしたいと思います。メインメモリーが4GBの場合、2.4GBになります。
とはいえ、何か区切りが悪いため、2GiBをzramに指定してみました。MiBで指定すれば、もっと細かい容量が指定可能だと思います。(区切りが悪い=人間の感覚ではなくマシンの感覚であるバイト境界の意味
一時的にzramを作成する場合
モジュールの読み込み
zramctlコマンドを使用する前に、zramのモジュールをロードする必要があります。
sudo modprobe zram
画面キャプチャでは、デバイスの数を指定しています。2つの場合、/dev/zram0と/dev/zram1を使用可能になるようです。
zramの作成
/dev/zram0作成後、mkswapでファイルシステムを作成、swaponでスワップ領域に追加します。
sudo zramctl -f -s 2048M
sudo mkswap /dev/zram0
sudo swapon -p 100 /dev/zram0
# 確認
swapon -s
zramctlのオプションは、-sにてサイズを指定し、-fにて自動検索、空いているデバイスを検索して、/dev/zram0を作成しています。
いわゆるRAMディスクのため、mkswapコマンドは一瞬で完了します。
Raspberry Pi OSは、既定で100MBのswapファイルが作成されていました。作成した2GiBのzramと合わせて、2.1GiBのswapが使用可能になりました。
起動時にzramを自動作成する場合
先程作成したzramは、再起動すると消えてしまいます。
OS起動時に、自動的にzramのswapを作成してみましょう。
udevルール作成
起動時にzramモジュールを読み込み、/dev/zram0を作成するように、udevのルールを作成します。
cat << EOF | sudo tee /etc/udev/rules.d/99-zram.rules
ACTION=="add", KERNEL=="zram0", ATTR{comp_algorithm}="zstd", ATTR{disksize}="2G",RUN="/usr/sbin/mkswap /dev/%k", TAG+="systemd"
EOF
zramのサイズは、ここで指定しておきます。ここでは2GiBにしています。
またmkswapコマンドをここで指定して、swapファイルシステムを作成しています。
メインメモリーの容量が8GBの場合、もっと大きくても良い気もしますし。いやいや、そこまでたくさんジョブ(プロセス)を作るのかな?という気もしますし。
最大6割程度で、不足している分、少しずつ容量を増やす感じが良いかもしれません。
fstabにマウント情報追加
cat << EOF | sudo tee -a /etc/fstab
/dev/zram0 none swap defaults,pri=100 0 0
EOF
/etc/fstabに1行追加しました。
プライオリティ、優先度pri=100ですが、-1から32767までの値を指定可能で、数値が大きいほど優先度は高くなります。指定しない場合、既定は-1になり、既存のswapファイルと重なるため、指定する必要があると思います。
再起動後にzramが有効かどうか確認
このような感じで、再起動後に自動的に2GiBのzramがswap領域として追加されました。
優先度も既存の/var/swapより高いため、microSDカードやSSDの寿命の延長につながりそうです。
他のswap・zram作成手段
既定ではdphys-swapfileにてswapファイル作成
Raspberry Pi OS(bullseye)では、dphys-swapfileにてswapファイルのマウント・アンマウントが行われているようです。
設定ファイルは、/etc/dphys-swapfileになります。
/etc/fstabファイルを見ますと、「ここにswapの設定を書かないように」という警告が記載されています。
理由は、dphys-swapfileの仕組みと重なるためかと思います。
zramの作成ですが、dphys-swapfileには、zramを作成する仕組みが無いようです。
このため、/etc/fstabの警告を無視して、dphys-swapfileの設定と共存するかたちで、設定を行っています。
dphys-swapfileのユニットを止めず、設定も変更しない理由は、zramが不足した場合はswapfileを使用したい、という理由があります。(容量100MBしか無いけど
systemd zram-generator
zramを作成する別の手段として、systemdのzram-generatorが挙げられます。
設定は/etc/systemd/zram-generator.confで行いますが。
現状、Raspberry Pi OSには、zram-generatorは組み込まれていないように見えます。
aptコマンドによるインストールの手段も提供されていないようです。
またzram-toolsを使用する手段もありますが。いずれにせよ、「zramモジュールを読み込んで、/dev/zram0デバイスを作成する」という目的のために、複数の手段が提供されているという認識です。
今回は、最もシンプルかつ最短の方法として、zramctlコマンドを使用したかたちになります。zramctlコマンドは、linuxカーネルが提供するコマンドになります。(最もシンプルかつ高信頼性あり
シングルボードコンピュータを使っていて、swapの発生、プロセスのファイルシステムへの退避が始まっているかどうかは、普段、あまり気にしていないかと思いますが。
冒頭で書かせて頂いた、カーネルやアプリのコンパイル等でmake -j オプションを使用すると、マシンの動作が不安定になる場合がありますが、これは確かにswapが発生しています。
何かサーバとして使用する場合など、プロセスが大量に作られる使い方では、swapは確実に発生します。たとえばhttpdプロセス等、セッションやコネクションの数に比例して作られるプロセスもあり、暇なプロセスはswapへ退避されます。
swap動作により、microSDカードやSSDの書き込みが発生し、寿命が縮むのは確かです。
zramを使用することで、ストレージの寿命を伸ばしつつ、さらにメモリー内で動作ということで、高速にswapが行われるようになります。
マシンの使用目的に応じて、必要がありましたら、zramの使用も検討してみて下さい。