os:centos7
テストファイル:a.txt 1.2G
監視コマンド:iostat -xdm 1
The first scene:
cp a.txt b.txt #b.txt is not exist
The second scene:
cp a.txt b.txt #b.txt is exist
最初のシーンがIOを消費しないのに、2番目のシーンがIOを消費するのはなぜですか?
最初のcp
操作中にデータがディスクにフラッシュされなかったが、2番目の操作中にデータがフラッシュされた可能性があります。
vm.dirty_background_bytes
を1048576(1 MiB)などの小さな値に設定して、これが当てはまるかどうかを確認してください。 sysctl -w vm.dirty_background_bytes=1048576
を実行すると、最初のcp
シナリオでI/Oが表示されます。
同期および/または直接I/Oの場合を除いて、ディスクへの書き込みは、しきい値に達するまでメモリにバッファリングされます。しきい値に達すると、バックグラウンドでディスクへのフラッシュが開始されます。このしきい値には正式な名前はありませんが、vm.dirty_background_bytes
とvm.dirty_background_ratio
によって制御されるため、「ダーティバックグラウンドしきい値」と呼びます。 カーネルドキュメントから :
vm.dirty_background_bytes
バックグラウンドカーネルフラッシャースレッドがライトバックを開始するダーティメモリの量が含まれます。
注:
dirty_background_bytes
はdirty_background_ratio
に対応します。一度に指定できるのはそのうちの1つだけです。一方のsysctlが書き込まれると、ダーティメモリ制限を評価するためにすぐに考慮され、もう一方は読み取られると0として表示されます。
dirty_background_ratio
空きページと再利用可能なページを含む使用可能な合計メモリのパーセンテージとして、バックグラウンドカーネルフラッシャースレッドがダーティデータの書き込みを開始するページ数が含まれます。
使用可能なメモリの合計は、システムメモリの合計と同じではありません。
vm.dirty_bytes
およびvm.dirty_ratio
これを超えて、2番目のしきい値があります。まあ、しきい値よりも制限があり、それはvm.dirty_bytes
とvm.dirty_ratio
によって制御されます。繰り返しになりますが、正式な名前がないため、「ダーティリミット」と呼びます。十分なデータが「書き込まれる」が、基になるブロックデバイスにコミットされない場合、write
をさらに試行すると、書き込みI/Oが完了するまで待機する必要があります。 (彼らが待機しなければならないデータの正確な詳細は私にはわかりません。I/ Oスケジューラの機能である可能性があります。わかりません。)
ディスクが遅い。スピニングRust特にそうなので、ディスク上のR/Wヘッドが読み取り要求を満たすために移動している間、読み取り要求が完了して書き込み要求を開始できるまで、書き込み要求を処理することはできません。 (およびその逆)
これが、書き込み要求をメモリにバッファリングし、読み取ったデータをキャッシュする理由です。作業を低速のディスクから高速のメモリに移動します。最終的にデータをディスクにコミットするとき、処理するデータの量が十分にあるので、シーク時間を最小限に抑える方法でデータを書き込もうとすることができます。 (SSDを使用している場合は、ディスクシーク時間の概念をSSDブロックの再フラッシュに置き換えます。再フラッシュはSSDの寿命を消費し、遅い操作です。SSDは、さまざまな程度の成功を収めて、独自の書き込みで非表示にしようとします。キャッシング。)
カーネルがvm.dirty_background_bytes
およびvm.dirty_background_ratio
を使用してデータをディスクに書き込もうとする前に、バッファリングされるデータの量を調整できます。
書き込んでいるデータの量がディスクに到達する速さに対して多すぎる場合、最終的にはすべてのシステムメモリを消費します。まず、読み取りキャッシュがなくなります。つまり、メモリから処理される読み取り要求が少なくなり、ディスクから処理する必要があるため、書き込みがさらに遅くなります。それでも書き込みプレッシャーが解消されない場合は、最終的にはメモリ割り当てのように、書き込みキャッシュが解放されるのを待つ必要があり、それはさらに混乱を招きます。
つまり、vm.dirty_bytes
(およびvm.dirty_ratio
)があります。 「ちょっと待ってください。これがさらに悪化する前に、実際にディスクにデータを取得する時が来ました」と言うことができます。
ただし、I/Oをハードストップすることは非常に混乱を招きます。ディスクは読み取りプロセスの観点からすでに低速であり、そのデータがフラッシュされるまでに数秒から数分分かかる場合があります。 vm.dirty_bytes
のデフォルトの20を検討してください。16GiBのRAMでスワップがないシステムの場合、3.4GiBのデータが取得されるのを待つ間にI/Oがブロックされることがあります。ディスクにフラッシュされました。128GiBのRAMを搭載したサーバーでは、27.5GiBのデータを待機している間、サービスがタイムアウトになります。
したがって、vm.dirty_bytes
(または必要に応じてvm.dirty_ratio
)をかなり低く保つと便利です。これにより、このハードしきい値をヒットすると、サービスへの影響を最小限に抑えます。
これらの調整機能を使用すると、スループットとレイテンシーの間で常にトレードを行うことができます。バッファリングが多すぎると、スループットは向上しますが、レイテンシはひどくなります。バッファリングが少なすぎると、スループットはひどくなりますが、レイテンシは大きくなります。
ディスクが1つしかないワークステーションやラップトップでは、vm.dirty_background_bytes
を約1MiBに設定し、vm.dirty_bytes
を8MiBから16MiBの間に設定するのが好きです。シングルユーザーシステムで16MiBを超えるスループットのメリットを見つけることはめったにありませんが、Webブラウザーのデータストアなどの同期ワークロードでは、レイテンシーのハングアップがかなり悪化する可能性があります。
ストライプパリティ配列を使用する場合は、配列のストライプ幅の倍数がvm.dirty_background_bytes
の適切な開始値であることがわかります。パリティの更新中に読み取り/更新/書き込みシーケンスを実行する必要が生じる可能性を減らし、アレイのスループットを向上させます。
vm.dirty_bytes
の場合、サービスが受ける可能性のある遅延の量によって異なります。私自身、ブロックデバイスの理論上のスループットを計算し、それを使用して100ミリ秒程度で移動できるデータ量を計算し、それに応じてvm.dirty_bytes
を設定するのが好きです。 100msの遅延は非常に大きいですが、(私の環境では)壊滅的ではありません。
ただし、これはすべて環境によって異なります。これらは、自分に適したものを見つけるための出発点にすぎません。