環境
以下のCentOS7環境で検証しています。
$ uname -r 3.10.0-327.13.1.el7.x86_64
設定パラメータ
Linuxのページキャッシュの書き出しを設定する主なパラメータは以下です。
バッファをバイパスするI/O(O_DIRECTなど)例外を除いて、通常の書き出し処理は一旦ダーティーページに書かれて後から遅延書き込みされます。
$ sysctl -a | grep dirty vm.dirty_background_bytes = 0 vm.dirty_background_ratio = 10 vm.dirty_bytes = 0 vm.dirty_expire_centisecs = 3000 vm.dirty_ratio = 40 vm.dirty_writeback_centisecs = 500
パラメータ名 | 内容 |
---|---|
vm.dirty_background_ratio | 単位はパーセンテージ。ダーティーなページの割合がこの値に達すると優先度の低いバックグラウンドでpdflushが書き出し動作する。 |
vm.dirty_ratio | 単位はパーセンテージ。ダーティーなページの割合がこの値に達すると優先度の高いフォアグランドでpdflushが書き出し動作する。 |
vm.dirty_bytes | vm.dirty_ratioとほぼ同じ。バイト単位で細かくチューニングしたい場合使う。0は無効化。 |
vm.dirty_background_bytes | vm.dirty_background_ratioとほぼ同じ。バイト単位で細かくチューニングしたい場合使う。0は無効化。 |
vm.dirty_writeback_centisecs | pdflushスレッドの起動間隔。単位は1/100秒。0にするとpdflushの定期実行は無効化される。 |
vm.dirty_expire_centisecs | ダーティーページの保持期間。この期間を超えると次回のpdflushで書き出される。単位は1/100秒。 |
CentOS7などtunedが有効化されている環境は単純にsysctlで変更するだけでは設定値が反映されないので注意です。
CentOS7再起動でsysctlで設定したカーネルパラメータが反映されないのはTunedが原因だった - YOMON8.NET
計測ツール
1 ダーティーページ状況の計測ツール
ダーティーページの状況や、書き出し状況は以下のワンライナーで計測しています。
while true; do sleep 1; cat /proc/{vmstat,meminfo} | egrep "^nr_dirty|^nr_writeback" | awk 'BEGIN{print strftime("%H:%M:%S\t")}{print $2 "\t"}' | tr -d "\n"; echo ""; done
出力項目
タブ区切りで以下の項目を出力します。
列番 | 項目 | 内容 |
---|---|---|
1 | date | 時間 |
2 | nr_dirty | ダーティページの数 |
3 | nr_writeback | ディスクにライトバック(書き戻された/書き出された)ページの数 |
4 | nr_writeback_temp | writeback時に使われることがある一時的なバッファ。ほとんど計測値に表れないと思います。 |
5 | nr_dirty_threshold | ダーティーページ数がこの値を超えるとpdflushによる書き込みがフォアグラウンドで走る。vm.dirty_ratioまたはvm.dirty_bytesで調整可能。 |
6 | nr_dirty_background_threshold | ダーティーページ数がこの値を超えるとpdflushによる書き込みがバックグラウンドで走る。vm.dirty_background_ratioまたはvm.dirty_background_bytesで調整可能。 |
出力フォーマットと出力例
フォーマット
date nr_dirty nr_writeback nr_writeback_temp nr_dirty_threshold nr_dirty_background_threshold
出力例
16:19:36 37 0 0 147729 49243 16:19:36 38 0 0 147897 49299 16:19:37 40 0 0 148050 49350 16:19:38 41 0 0 148062 49354 16:19:39 41 0 0 148052 49350
2 時間付きvmstat
説明は省略 dstat -tv
とかでもOK。特に注目するのは bo
と wa
の項目。
vmstat 1 | awk '{print strftime("%H:%M:%S\t"),$0}'
3 fio(I/O負荷発生ツール)
I/O負荷をかけるにはfioが便利です。こちらも詳細は省きますが、コマンド例です。 direct=1
とか fsync=1
のオプションを付けて動きの違いを見るとわかりやすいかもしれないです。
fioが入っていない環境の場合はepelからインストールしてください。dd使っても同じような検証は可能です。
fio -filename=/your/file/path -rw=randwrite -bs=4k -size=3G -numjobs=15 -group_reporting -name=job01 -engine=libaio
また上記に合わせて同時に iostat -txm 1
とかも取得すると動きが良くわかります。
観測
fioを実行しながら、上で挙げたダーティーページ状況の計測ツールを使って状況を観測してみます。
11:04:54 20 0 0 418745 139581 11:04:55 106072 0 0 401404 133801 11:04:56 190426 1193 0 400360 133453 #<- nr_dirtyがnr_dirty_thresholdまたはnr_dirty_background_thresholdを超過し書き込みが始まる 11:04:57 245946 8425 0 400152 133384 11:04:58 248485 16430 0 400097 133365 11:05:00 244314 28352 0 400123 133374 11:05:01 241633 34827 0 400224 133408 #<- この辺りでfioによる書き込みは終わっている 11:05:02 165506 29078 0 400153 133384 11:05:03 119912 2008 0 418430 139476 #<- nr_dirtyがnr_dirty_background_thresholdを下回り書き込みが終了 11:05:04 119914 0 0 418336 139445 #<-nr_writebackが0(書き込み無い状態)が続く 11:05:05 119915 0 0 418353 139451 11:05:06 119916 0 0 418360 139453 11:05:07 119917 0 0 418347 139449 11:05:08 29023 738 0 418304 139434 #<-dirty_writeback_centisecsの5秒が経過してpdflushが再度起床されて書き込みが動く 11:05:09 17717 420 0 418124 139374 11:05:10 7021 577 0 418113 139371 11:05:11 30 79 0 418156 139385 #<-dirty_pageが少なくなりdirty_bytesやdirty_expire_centisecsに沿って処理される 11:05:12 13 0 0 418176 139392 11:05:13 15 0 0 418171 139390
実験
理解を深めるために例えばこんな極端な設定にしてみます。
$ sysctl -a | grep dirty vm.dirty_background_bytes = 0 vm.dirty_background_ratio = 89 vm.dirty_bytes = 0 vm.dirty_expire_centisecs = 3000 vm.dirty_ratio = 90 vm.dirty_writeback_centisecs = 0
ダーティーページが溜まっても dirty_ratio
や dirty_background_ratio
で設定した閾値に届かないのでpdflushが起床されません。
dirty_expire_centisecs
によって30秒経ったダーティーページは書き出し対象となりますが、dirty_writeback_centisecs
が0と設定されているのでpdflush定期実行もされず、ずっとメモリ上に残った状態となります。
13:17:00 786481 0 0 1018808 1007488 13:17:01 786484 0 0 1018476 1007159 13:17:02 786488 0 0 1014818 1003542 13:17:03 786490 0 0 1015298 1004017 13:17:04 786490 0 0 1014252 1002982 13:17:05 786492 0 0 1015057 1003779 13:17:06 786494 0 0 1015271 1003990 13:17:07 786496 0 0 1014851 1003575
当然vmstatで確認してみてもboの部分の値見ても書き込み行われてないです。(下の例はmysqlがページキャッシュをスルーしてDirect IOしている値が少し出てしまってますが。。)
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 13:16:59 0 0 0 394360 948 5473796 0 0 0 6 613 718 8 7 86 0 0 13:17:00 0 0 0 391196 948 5473776 0 0 0 6 325 516 4 1 96 0 0 13:17:01 1 0 0 386808 948 5473708 0 0 4 15 1559 1751 32 5 64 0 0 13:17:02 1 0 0 381108 948 5473748 0 0 0 14 2093 1623 55 9 37 0 0 13:17:03 1 0 0 380324 948 5473756 0 0 4 11 2032 1550 55 7 38 0 0 13:17:04 2 0 0 375196 948 5473740 0 0 0 7 2193 2022 50 10 40 0 0 13:17:05 1 0 0 377568 948 5473744 0 0 0 9 2244 2184 48 12 40 0 0 13:17:06 0 0 0 380456 948 5473752 0 0 0 9 1737 2062 30 7 64 0 0 13:17:07 1 0 0 377244 948 5473756 0 0 0 7 1672 1786 32 7 62 0 0
sync
コマンド売ってみると一気に書き込みが始まります。
$ sync
残ってたダーティーページが一掃されました。
13:25:32 787079 0 0 1018037 1006726 13:25:33 660539 41994 0 1018018 1006707 13:25:34 617478 43034 0 1017894 1006584 13:25:35 486411 44049 0 1017872 1006562 13:25:36 351217 46082 0 1017941 1006630 13:25:37 208905 48130 0 1017923 1006613 13:25:38 58387 51199 0 1017256 1005953 13:25:39 2 0 0 1019179 1007855
vmstatでもboの列にディスクに書き出した値が出ています。
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 13:25:32 r b swpd free buff cache si so bi bo in cs us sy id wa st 13:25:32 1 0 0 386516 948 5476288 0 0 0 6 323 510 3 1 97 0 0 13:25:33 1 1 0 386116 948 5476544 0 0 0 481326 1345 716 5 5 62 28 0 13:25:34 0 2 0 386164 948 5476680 0 0 0 179720 1100 593 5 2 0 93 0 13:25:35 0 2 0 386256 948 5476684 0 0 0 489996 2308 608 3 4 0 93 0 13:25:36 0 2 0 385728 948 5476688 0 0 0 526860 1762 696 7 5 42 46 0 13:25:37 0 2 0 385820 948 5476664 0 0 0 560140 1453 547 4 5 48 43 0 13:25:38 0 2 0 383104 948 5476668 0 0 0 505868 1510 723 6 5 46 44 0 13:25:39 0 0 0 391212 948 5476668 0 0 0 404499 1366 642 4 3 53 40 0 13:25:40 0 0 0 389420 948 5476588 0 0 4 10 437 674 6 1 93 0 0 13:25:41 0 0 0 389348 948 5476560 0 0 0 7 313 524 3 0 97 0 0
このようにパラメータを動かしながら実験繰り返すと動きが理解しやすいと思います。
チューニング例
デフォルト値
vm.dirty_background_bytes = 0 vm.dirty_background_ratio = 10 vm.dirty_bytes = 0 vm.dirty_expire_centisecs = 3000 vm.dirty_ratio = 40 vm.dirty_writeback_centisecs = 500
いくつかあるパラメータの中でも、特にポイントとなるのはvm.dirty_ratio
とvm.dirty_background_ratio
です。
また、チューニングの前にI/Oネックになっているアプリケーションの挙動はperfなどのツールを使ってチェックしておく必要があります。O_DIRECTでアクセスしていないかや、fsyncのタイミングなどはチェックしておかないとそもそもの動きが把握できなかったりします。
ダーティーページの最小化
調べて見ると、これが一番よく見られるチューニングです。
pdflush起動までの閾値( dirty_ratio
, dirty_background_ratio
)を両方下げます。これによりダーティーページが積極的にディスクに書き出されて、OS上に残ることが少なくなります。
例えば以下のようなメリットがあると考えられます。 ・電源障害時などの被害を最小化 ・ページキャッシュの解放
ストレージ側にも大きなキャッシュがある場合などは、より有効な可能性があります。
設定例
vm.dirty_ratio = 20 #default : 40 vm.dirty_background_ratio = 5 #default : 10
他にも vm.dirty_writeback_centisecs
を短くすることも検討の余地ありです。
キャッシュ有効活用メモリ上に乗せたまま高速処理
上とは逆にpdflush起動までの閾値( dirty_ratio
, dirty_background_ratio
)を両方上げます。
こうすることでメモリ上にダーティーなページを溜め込む形になります。その分一回の書き出しは大きくなります。メモリ上置いたまま高速に処理を回すことができるアプリケーションなら検討の余地あるかもしれません。
設定例
vm.dirty_ratio = 60 #default : 40 vm.dirty_background_ratio = 20 #default : 10
他にも dirty_writeback_centisecs
や dirty_expire_centisecs
を上げたりも検討可能です。
電源障害時などはより多くのデータがロストすることに注意です。
局所的なI/O負荷を受け流したい
普段はメモリだけで処理して、ほとんどI/O発生しないが、局所的にはI/O負荷が高くなるシステムの場合など。 dirty_ratio
を上げて、 dirty_background_ratio
を下げる方法があります。
これにより、ダーティーなページは裏側バックグラウンドで書き出されることになります。局所性によるI/Oの待ち行列を慣らしてあげることが可能です。
dirty_background_ratio
で起床したバックグラウンド処理の場合はデータ書き出しに想像以上の時間がかかる場合があるので、念入りに検証が必要です。
大きな書き込みがあると一気に dirty_ratio
の閾値に到達してしまい意図した動作をしない場合があります。その場合は、 dirty_ratio
の値をさらに上げてみたり、 dirty_writeback_centisecs
を下げて処理書き出し間隔を短くしたり、ファイルなどの書き出し帯域を絞ってバックグラウンドが書き出す時間を確保してみたり調整が必要です。
vm.dirty_ratio = 60 #default : 40 vm.dirty_background_ratio = 5 #default : 10
この手法も電源障害時などはより多くのデータがロストすることに注意です。
参考URL
linux/vm.txt at 6e5c8381d1db4c1cdd4b4e49d5f0d1255c2246fd · torvalds/linux · GitHub