RAMディスク:RAMディスクの利点とパフォーマンスの謎
ラムディスク(RAMディスクとも呼ばれます)とは、メモリの一部をディスクとして扱う方法です。少し考えてみると、そのメリットとデメリットは明らかです。
- RAM は最速のディスクよりもはるかに高速であるため、RAM ディスクでの操作は、NVMe、SSD、そしてもちろん回転ディスクを使用する場合よりもはるかに高速です。
- しかし、RAMは揮発性です。サーバーが再起動したりクラッシュしたりすると、RAMディスク上のデータはすべて失われます。
RAMディスクは、キャッシュ、セッションファイル、その他の一時データを保存するのに最適な場所です。データベースジャーナル(Postgresの先行書き込みログ、OracleのREDOログなど)をRAMディスクに保存し、システムのシャットダウン/起動時に永続ストレージにコピーして復元したり、クラッシュに備えて頻繁にバックアップを実行したりする設定も行っています。
RAMディスクの設定と使い方を見てみましょう。楽しみのために、大容量の24GB Linodeシステムを起動してみました。
root@bigmem:~# free -m 合計 使用済み 無料 共有 バフ/キャッシュ 利用可能 メモ: 24049 65 23913 0 70 23732 スワップ: 511 0 511
システムを再構成して再起動する必要があると思われるかもしれませんが、実際はもっと簡単です。
root@bigmem:~# mkdir /ramdisk root@bigmem:~# マウント -t tmpfs -o サイズ=16G ramdisk16 /ramdisk root@bigmem:/ramdisk# df -h /ramdisk ファイルシステム サイズ 使用済み 利用可能 使用率 マウント済み ramdisk16 16G 0 16G 0% /RAMディスク
本当にこれだけです。ここでの「ramdisk16」は私が勝手に付けた名前です。このパラメータは、マウントコマンドの一般的な形式(「mount [type] [options] [device] [mountpoint]」)のために必要だと考えています。「device」という名前自体がないので、プレースホルダーを使用しています。
「ramdisk」という用語は少し誤解を招く可能性があることに注意してください。ramdisk は、ファイルシステムなどを作成するための何らかの /dev/sdX などのデバイスを取得するものと考えるからです。ramdisk は、実際には、事前に作成されたディスク上の「ram ファイルシステム」と考えることができます。
/ramdisk では、ディレクトリの作成、ファイルの追加など、やりたいことは何でもできるようになりました。しかし、アンマウント(またはシステムの再起動)すると、すべてが失われてしまいます。/etc/fstab にエントリを永続化することはできますが、もちろんこれは、再起動時に RAM ディスクが空のマウントとして再作成されることを意味します。
ramdisk16 /ramdisk tmpfs デフォルト、サイズ=16G 0 0
それで、本当に速くなるのでしょうか? 見てみましょう。そして、頭を悩ませる話もお楽しみに!
ioping
ioping ツールを使用して、SSD ディスクは次のようになります。 root@bigmem:/# ioping 。 4 KiB <<< . (ext4 /dev/sda 19.2 GiB): リクエスト=1 時間=82.2 us (ウォームアップ) 4 KiB <<< . (ext4 /dev/sda 19.2 GiB): リクエスト=2 時間=933.8 us 4 KiB <<< . (ext4 /dev/sda 19.2 GiB): リクエスト=3 時間=304.4 us 4 KiB <<< . (ext4 /dev/sda 19.2 GiB): リクエスト=4 時間=306.1 us 4 KiB <<< . (ext4 /dev/sda 19.2 GiB): リクエスト=5 時間=279.4 us 4 KiB <<< . (ext4 /dev/sda 19.2 GiB): リクエスト=6 時間=337.5 us ^C --- . (ext4 /dev/sda 19.2 GiB) ioping 統計 --- 5 件のリクエストが 2.16 ミリ秒で完了、20 KiB の読み取り、2.31 k iops、9.04 MiB/s 5.63 秒で 6 件のリクエストを生成しました。24 KiB、1 iops、4.26 KiB/s 最小/平均/最大/平均偏差 = 279.4 us / 432.2 us / 933.8 us / 251.4 us
一方、RAM ディスクでも同じことを実行します。 root@bigmem:/# cd /ramdisk/ root@bigmem:/ramdisk# ioping 。 4 KiB <<< . (tmpfs ramdisk16 16 GiB): リクエスト=1 時間=1.76 us (ウォームアップ) 4 KiB <<< . (tmpfs ramdisk16 16 GiB): リクエスト=2 時間=8.43 us 4 KiB <<< . (tmpfs ramdisk16 16 GiB): リクエスト=3 時間=12.1 us 4 KiB <<< . (tmpfs ramdisk16 16 GiB): リクエスト=4 時間=11.8 us 4 KiB <<< . (tmpfs ramdisk16 16 GiB): リクエスト=5 時間=10.2 us 4 KiB <<< . (tmpfs ramdisk16 16 GiB): リクエスト=6 時間=9.30 us 4 KiB <<< . (tmpfs ramdisk16 16 GiB): リクエスト=7 時間=9.66 us ^C --- . (tmpfs ramdisk16 16 GiB) ioping 統計 --- 6 件のリクエストが 61.5 マイクロ秒で完了、24 KiB の読み取り、97.6 k iops、381.3 MiB/s 6.48 秒で 7 件のリクエストを生成しました。28 KiB、1 iops、4.32 KiB/s 最小/平均/最大/平均偏差 = 8.43 us / 10.2 us / 12.1 us / 1.32 us
パーセントの差を計算するつもりでしたが、それは必要ないと思います。
dd 書き込みと読み取り
1GB のファイルを送信してみましょう。
root@bigmem:/ramdisk# time dd if=/dev/zero of=/ramdisk/1gbfile bs=1MB count=1024 1024+0件のレコード 1024+0 レコード出力 1024000000バイト(1.0 GB、977 MiB)をコピー、0.38423秒、2.7 GB/秒 実数 0分0秒450秒 ユーザー 0m0.000s システム 0分0.448秒
さて、ここで興味深い点があります。2GBのファイルは2倍くらい時間がかかると予想していましたが、実際その通りです。しかし、4GBのファイルだとどれくらい時間がかかるのでしょうか?あるいは8GBだと?明らかに直線的に時間がかかるわけではありません。例えば、以下のような場合です。
| RAMディスクファイルサイズ | ddで割り当てる時間 |
| 1GB | 約0.4秒 |
| 2GB | 約0.75秒 |
| 4ギガバイト | 約32秒 |
| 8GB | 約145秒 |
私の理論では、物理ホストサーバーは1GBか2GBのRAMならかなり簡単に確保でき、おそらくそのくらいの容量のメモリが余っているはずです。しかし、8GBの空きメモリを見つけるには、より集中的に空きメモリを探す必要があります。私の頭の中での例えは、駐車場に行って車を1台停めたいのと、32台駐車したいのとでは違います。駐車場には十分なスペースがあるのですが、空きスペースを見つけるのに少し時間がかかります。
ラムディスクに戻りましょう。ラムディスクとNVMeを比較してみましょう。ラムディスク:
root@bigmem:/ramdisk# for run in 1 2 3 ; do time dd if=/dev/zero of=/ramdisk/2gbfile bs=1MB count=2048 ; done 2048+0件のレコード 2048+0 件のレコードが出力されました 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.727246秒、2.8 GB/秒 実数 0分0.853秒 ユーザー 0m0.000s システム 0分0.851秒 2048+0件のレコード 2048+0 件のレコードが出力されました 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.729331秒、2.8 GB/秒 実数 0分0.855秒 ユーザー 0m0.000s システム 0分0.853秒 2048+0件のレコード 2048+0 件のレコードが出力されました 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.726534秒、2.8 GB/秒 実数 0分0.853秒 ユーザー 0m0.000s システム 0分0.851秒
つまり約0.85秒です。NVMe:
root@bigmem:/ramdisk# for run in 1 2 3 ; do time dd if=/dev/zero of=/2gbfile bs=1MB count=2048 ; done 2048+0件のレコード 2048+0 件のレコードが出力されました 2048000000バイト(2.0 GB、1.9 GiB)をコピー、1.86907秒、1.1 GB/秒 実数 0分2秒059秒 ユーザー 0m0.000s システム 0分1.441秒 2048+0件のレコード 2048+0 件のレコードが出力されました 2048000000バイト(2.0 GB、1.9 GiB)をコピー、1.66434秒、1.2 GB/秒 実数 0分1秒855秒 ユーザー 0m0.000s システム 0分1.437秒 2048+0件のレコード 2048+0 件のレコードが出力されました 2048000000バイト(2.0 GB、1.9 GiB)をコピー、1.69488秒、1.2 GB/秒 実数 0分1秒887秒 ユーザー 0分0.004秒 システム 0分1.424秒
では、次の読み取りを試してみましょう。
root@bigmem:/ramdisk# for run in 1 2 3 ; do time dd if=/ramdisk/2gbfile of=/dev/null bs=1024k ; done 1953+1の記録 1953+1のレコードがリリース 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.183827秒、11.1 GB/秒 実数 0分0.185秒 ユーザー 0m0.000s システム 0分0.185秒 1953+1の記録 1953+1のレコードがリリース 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.18002秒、11.4 GB/秒 実数 0分0.181秒 ユーザー 0m0.000s システム 0分0.181秒 1953+1の記録 1953+1のレコードがリリース 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.180192秒、11.4 GB/秒 実数 0分0.181秒 ユーザー 0m0.000s システム 0分0.181秒 root@bigmem:/ramdisk# for run in 1 2 3 ; do time dd if=/2gbfile of=/dev/null bs=1024k ; done 1953+1の記録 1953+1のレコードがリリース 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.172908秒、11.8 GB/秒 実数 0分0.174秒 ユーザー 0m0.000s システム 0分0.174秒 1953+1の記録 1953+1のレコードがリリース 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.235156秒、8.7 GB/秒 実数 0分0.236秒 ユーザー 0m0.000s システム 0分0.236秒 1953+1の記録 1953+1のレコードがリリース 2048000000バイト(2.0 GB、1.9 GiB)をコピーしました。0.171044秒、12.0 GB/秒 実数 0分0.172秒 ユーザー 0m0.000s システム 0分0.172秒
これらの数値を見ると、OSのキャッシュがディスクに大きく貢献していると思われます。これは良いことです。レイテンシと書き込み速度は、予想通りRAMディスクの方がはるかに優れています。特に書き込み速度は、CPUオペコード(RAMディスク)を1つ実行するのと、ストレージデバイスとやり取りしてデータのコミットを要求し、応答を待つのとでは大きく異なります。もちろん、これらはすべて非常に高速ですが、メインメモリの外部に一切アクセスしないものほど高速ではありません。