#初めに
久しぶりに Fedora (fedora 33) を触ったところ、swap が swap-on-zram という見慣れない形式に変わっていたので zram について調べてみました
#サマリー
- メモリ上にブロックデバイスを構成し、そこに書き込むデータを圧縮することにより高速な I/O とメモリ領域の有効活用を行う技術
要は圧縮機能付き RAM Disk です。 swap や /tmp, /var の一部キャッシュなどの用途に使われることが想定されているようです。
「swap をメモリ上に置く」と聞くと本末転倒な印象を受けますが、メモリ上のあまり使われていないブロックを圧縮する、というとすんなり理解ができると思います。(ただしこれは正確な表現ではありません)
また、圧縮する際に中間データなどを Disk 上に置かないようにすることにより、Disk I/O を排除し高速化が図られています。
Disk 上の swap 領域との I/O よりも、メモリ上の圧縮/展開の方が高速なため、「メモリ上の swap 領域」というものが実現されます。
メモリを大量に使い swap まで含めた処理を行うような場合、Disk に swap out するよりも zram 上に swap out する方が(圧縮処理の時間はかかるものの)速いうえに、圧縮することにより swap も含めた仮想メモリ全体の容量も増えることになります。
以下、swap からは離れて、zram 自体について、zram: Compressed RAM based block devices に沿ってみていきたいと思います。
#環境
fedora 33 ( on KVM )
4GB メモリ
# lsmem
RANGE SIZE STATE REMOVABLE BLOCK
0x0000000000000000-0x000000007fffffff 2G オンライン yes 0-15
0x0000000100000000-0x000000017fffffff 2G オンライン yes 32-47
メモリブロックサイズ 128M
Total online memory: 4G
Total offline memory: 0B
# zramctl --output-all
NAME DISKSIZE DATA COMPR ALGORITHM STREAMS ZERO-PAGES TOTAL MEM-LIMIT MEM-USED MIGRATED MOUNTPOINT
/dev/zram0 1.9G 4K 74B lzo-rle 2 0 12K 0B 12K 0B [SWAP]
# zramctl -h (※抜粋)
利用可能な出力の列:
NAME zram デバイス名
DISKSIZE 圧縮前のデータ容量による制限
DATA 圧縮前の格納されたデータのサイズ
COMPR 圧縮後の格納されたデータのサイズ
ALGORITHM 選択された圧縮アルゴリズム
STREAMS 並行して実行される圧縮オペレーションの数
ZERO-PAGES empty pages with no allocated memory
TOTAL all memory including allocator fragmentation and metadata overhead
MEM-LIMIT memory limit used to store compressed data
MEM-USED memory zram have been consumed to store compressed data
MIGRATED number of objects migrated by compaction
MOUNTPOINT マウントされている場所
※ zramctl は util-linux パッケージに含まれています
# free -m
total used free shared buff/cache available
Mem: 3928 165 2705 0 1057 3538
Swap: 1963 0 1963
#zram 試してみた
free -m
を見る限り、 メモリ量としては 4GB と認識されているようです。
また、 vmstat 1 1
を見ても、 おおよそ 4GB ありそうです。
そのため、正確な根拠はありませんが、OS から見たメモリ量としては 4GB のままのようです。
(なお、zram を削除しても free -m の total 値は変わりませんでした)
zram の作成(zramctl)
swap は操作が面倒なので、ファイルシステムとして作成してみます。
下記の例の zram0 は swap on zram で利用されています。
zramctl コマンドで追加することができます。
# zramctl -f -s 500M
/dev/zram1
##zram の構成概要確認
zram の各種内容は zramctl --output-all
で確認できます。
# zramctl --output-all
NAME DISKSIZE DATA COMPR ALGORITHM STREAMS ZERO-PAGES TOTAL MEM-LIMIT MEM-USED MIGRATED MOUNTPOINT
/dev/zram1 500M 0B 0B lzo-rle 2 0 0B 0B 0B 0B
/dev/zram0 1.9G 4K 74B lzo-rle 2 0 12K 0B 12K 0B [SWAP]
まだどこにもマウントしていないので、 MOUNT-POINT はブランクです。
また、ドキュメントによると、メモリブロックサイズの倍数に切り上げられるそうです。
##ファイルシステムの作成
mkfs コマンド等でファイルシステムを作成すると、圧縮 RAM Disk として利用可能です。
# mkfs.xfs /dev/zram1
meta-data=/dev/zram1 isize=512 agcount=4, agsize=32000 blks
= sectsz=4096 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1
data = bsize=4096 blocks=128000, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=1221, version=2
= sectsz=4096 sunit=1 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
Discarding blocks...Done.
ファイルシステムのマウント
# mkdir /data/zram1
# mount /dev/zram1 /data/zram1
# df -h
ファイルシス サイズ 使用 残り 使用% マウント位置
/dev/zram1 496M 29M 467M 6% /data/zram1
##zram ファイルシステムを埋めてみる
dd
コマンドを使って、ファイルシステムをデータで埋めてみます。
# pwd
/data/zram1
# dd if=/dev/urandom of=/data/zram1/randfile bs=1M count=1024
dd: '/data/zram1/randfile' の書き込みエラー: デバイスに空き領域がありません
467+0 レコード入力
466+0 レコード出力
488701952 bytes (489 MB, 466 MiB) copied, 3.4548 s, 141 MB/s
# df -h .
ファイルシス サイズ 使用 残り 使用% マウント位置
/dev/zram1 496M 495M 428K 100% /data/zram1
# zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram1 lzo-rle 500M 469M 466.1M 466.3M 2 /data/zram1
/dev/zram0 lzo-rle 1.9G 4K 74B 12K 2 [SWAP]
zramctl で見る限り、 データは 469MiB あり、 圧縮して 466.1MiB のようです。
urandom でランダム文字列を作成しているため、圧縮効率は低いです。
いったん削除してから zero で書き込みしてみます。
まず、ファイルを削除します。
# rm randfile
rm: 通常ファイル 'randfile' を削除しますか? y
# df -h .
ファイルシス サイズ 使用 残り 使用% マウント位置
/dev/zram1 496M 29M 467M 6% /data/zram1
# zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram1 lzo-rle 500M 469M 466.1M 466.3M 2 /data/zram1
ファイルを削除すると、 df
の空き容量は増えますが、 zramctl
の DATA サイズは減りません。
これは rm でファイルの i-node が削除されているだけで実データが残っているからだと思います。
次に、 zero で埋めてみます。
# dd if=/dev/zero of=/data/zram1/zerofile bs=1M count=1024
dd: '/data/zram1/zerofile' の書き込みエラー: デバイスに空き領域がありません
467+0 レコード入力
466+0 レコード出力
488701952 bytes (489 MB, 466 MiB) copied, 0.364888 s, 1.3 GB/s
# df -h .
ファイルシス サイズ 使用 残り 使用% マウント位置
/dev/zram1 496M 495M 428K 100% /data/zram1
# zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram1 lzo-rle 500M 469M 89K 256K 2 /data/zram1
/dev/zram0 lzo-rle 1.9G 4K 74B 12K 2 [SWAP]
df
コマンドでは 100% になっています。
zramctl
で見ると、 Data は 496MiB で urandom パターンと同じですが、圧縮されて 89KiB になっているようです。
結論としては、ブロックデバイスとして確保され、ユーザーとしての利用では指定したサイズとして利用可能ですが
物理的には圧縮されている分消費が少ないようです。
##zram削除 (zramctl)
zram の削除は zramctl -r
で削除します。
いきなり打ってエラーを起こしているのは unmount せずに実行したらどうなるのかを見たかっただけで
決して 忘れていた わけではありません。はい。
# zramctl -r /dev/zram1
zramctl: /dev/zram1: リセットに失敗しました: デバイスもしくはリソースがビジー状態です
# umount /data/zram1
# zramctl -r /dev/zram1
# zramctl
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram0 lzo-rle 1.9G 4K 74B 12K 2 [SWAP]
##zram とOS再起動
これも気になるところですね。 zram 再作成してデータを入れた状態を作ります。
# dd if=/dev/urandom of=/data/zram1/randfile bs=1M count=1024
dd: '/data/zram1/randfile' の書き込みエラー: デバイスに空き領域がありません
467+0 レコード入力
466+0 レコード出力
488701952 bytes (489 MB, 466 MiB) copied, 2.59002 s, 189 MB/s
# df -h .
ファイルシス サイズ 使用 残り 使用% マウント位置
/dev/zram1 496M 495M 428K 100% /data/zram1
# ls -l
合計 477248
-rw-r--r-- 1 root root 488701952 12月 5 23:46 randfile
この状態で OS 再起動します。
# shutdown -r now
...(略)
# ls -l /dev/zr*
brw-rw---- 1 root disk 251, 0 12月 5 23:47 /dev/zram0
デバイスレベルで消えているようです。まぁ、当たり前かもしれません。
(正直なところ、デバイスは残っていて中身だけ消えるのか、と思っていました。。)
##zram の構成詳細確認
zram の構成については /sys/block/zramX/
以下のファイルで確認することができます。
# cd /sys/block/zram1
# ls
alignment_offset compact disksize ext_range inflight max_comp_streams power reset stat
bdi debug_stat events hidden initstate mem_limit queue ro subsystem
capability dev events_async holders integrity mem_used_max range size trace
comp_algorithm discard_alignment events_poll_msecs idle io_stat mm_stat removable slaves uevent
zram: Compressed RAM based block devicesに記載があったのは以下のものです
ファイル | RW | 概要 |
---|---|---|
disksize | RW | デバイスのサイズの確認・設定 |
reset | WO | デバイスのリセット(消す) |
mem_limit | WO | 圧縮データを格納するのに使えるメモリの最大容量 |
max_comp_streams | RW | 圧縮処理の並列実行数 |
comp_algorithm | RW | 圧縮アルゴリズムの表示/指定 |
compact | WO | メモリコンパクションの実行トリガー |
backing_dev | RW | zram からの書き出し先ストレージデバイス |
mm_stat | RO | メモリの使用状況 |
cat mm_stat
を行った際の表示の内容について補足します。
(下記は zram0 (swap on zram) の例です )
# cat mm_stat
4096 74 12288 0 12288 0 0 0
項目(左から順) | 内容 |
---|---|
orig_data_size | 非圧縮状態でのサイズ(重複ページを除く) 単位:byte |
compr_data_size | 圧縮サイズ |
mem_used_total | アロケートされたメモリサイズ。フラグメンテーションやオーバーヘッドを含む。(よってデータサイズ合計と一致しない)。 スペースの利用効率は compr_data_size と mem_used_total で算出される。単位:byte |
mem_limit | 圧縮データの格納に利用できるメモリの最大サイズ |
mem_used_max | データ格納のために消費されたメモリの最大サイズ |
same_pages | 同じ内容のページの数。(1ページだけ保持され、他は同じなので保持されない) |
pages_compacted | メモリのコンパクションで解放されたページ数 |
huge_pages | 圧縮が効かないページ数 |
他にも stat, io_stat, bd_stat などがありいろいろな情報が確認できます。
詳しくは zram: Compressed RAM based block devices をご覧ください。
#zram 構成ファイルを用いたデバイスの操作
zram 追加
ここでは、 zram1 を zramctl を使わずに追加します。 /sys/class/zram-control/hot_add
を読むだけでデバイスが増えます。
(ある意味恐ろしい)
先程紹介した /sys/block/zramX/
ではなく、追加削除は /sys/class/zram-control/
以下の hot_add, hot_remove で行います。
# ls /dev/zram*
/dev/zram0
# cat /sys/class/zram-control/hot_add
1
# ls /dev/zram*
/dev/zram0 /dev/zram1
zram のサイズ指定
一度デバイスができてからは、 デバイスの関連ファイルで操作します。 /sys/block/zramX/
以下です。
# cat /sys/block/zram1/disksize
0
# echo 512M > /sys/block/zram1/disksize
# cat /sys/block/zram1/disksize
536870912
zram 圧縮アルゴリズム確認・指定
当記事では記載していませんが zramctl でも指定可能です
ファイルで指定する場合は、一度 reset する必要があるようです。
( zramctl コマンドでの reset はデバイスごと消えますが、 ここでのリセットはデバイスは消えず、
後で紹介する hot_remove で消えます)
# cat /sys/block/zram1/comp_algorithm
lzo [lzo-rle] lz4 lz4hc 842 zstd
# echo lz4 > /sys/block/zram1/comp_algorithm
-bash: echo: 書き込みエラー: デバイスもしくはリソースがビジー状態です
# echo 1 > /sys/block/zram1/reset
# ls -l /dev/zra*
brw-rw---- 1 root disk 251, 0 12月 5 23:47 /dev/zram0
brw-rw---- 1 root disk 251, 1 12月 6 00:17 /dev/zram1
# echo lz4 > /sys/block/zram1/comp_algorithm
# cat /sys/block/zram1/comp_algorithm
lzo lzo-rle [lz4] lz4hc 842 zstd
[] の位置が変わっているのがわかると思います。あと当然ではありますが、 reset したときにデータは消えますのでご注意ください。
zram 削除
削除は hot_remove を使います。 場所が違いますのでご注意を
# ls -l /dev/zra*
brw-rw---- 1 root disk 251, 0 12月 5 23:47 /dev/zram0
brw-rw---- 1 root disk 251, 1 12月 6 00:17 /dev/zram1
# echo 1 > /sys/class/zram-control/hot_remove
# ls -l /dev/zra*
brw-rw---- 1 root disk 251, 0 12月 5 23:47 /dev/zram0
この記事では、 swap on zram というところから zram の操作について簡単に調べたことをまとめました。
ここでは確認していませんが、 Backing Device を用意してディスクにデータを吐き出させるようなことも
できるようです。
詳しくは参考のドキュメントをご覧ください。
参考)
■Compcache: in-memory compressed swapping
https://lwn.net/Articles/334649/
■Zram
https://ja.wikipedia.org/wiki/Zram
■zram: Compressed RAM based block devices
https://www.kernel.org/doc/Documentation/blockdev/zram.txt