この記事は、ファイルの操作を低負荷で行いたい人のための記事です。
負荷をかけたくないケースとは
負荷は一般的に CPU 負荷と I/O 負荷に二分されますが、ここでは I/O 負荷にフォーカスして話を進めます。サーバ負荷をかけたくないケースの多くは、サービス運用中のサーバ上におけるメンテナンスです。少ない・小さいファイルを操作する分には問題ありませんが、大量・巨大なファイルを操作するとなるとシステム全体に影響を及ぼすような I/O 負荷がかかってしまいます。これでは、本来優先すべき運用中のサービスに影響が出てしまいますのでよろしくありません。そのため、多くのサーバ管理者は、低負荷でファイル操作を行う必要があります。
I/O 負荷がかかるとどうなるのか
Linux サーバに I/O 負荷がかかった場合、サーバ上の他のサービスに影響が出る可能性があります。例えば、Webサーバ上で数百GBのファイルや数万個のファイルを一気に削除しようとすると、Web サーバのレスポンスタイムが大幅に遅延するという問題が生じます。具体的には、ファイル操作を行おうとする他のプロセスが I/O 待ちとなってしまい、処理が一時的に停止する事象(すなわちサイト表示不可)が発生します。もちろん、軽微な非同期 I/O やディスクキャッシュへの I/O 処理についてはこの限りではありません。しかし、同期書き込みやディスクキャッシュが作成されていない状況で読み込みをする場合はこの問題が発生します。
I/O の仕組みについては昨年書いた卒論の 2 章にもまとめたのでよかったら読んでみてください。
ionice を使えばいいのでは?
今まで負荷に配慮してファイル操作を行ったことがある人なら誰もが知っている ionice コマンドというものがあります。ionice は、引数に指定したプロセス・コマンドに関する I/O 処理の優先度を指定するためのコマンドです。nice コマンドは、CPU 割り当ての優先度を指定します。ionice は、nice コマンドの I/O 版です。I/O 負荷をかけないように処理をしたい場合は、ionice コマンドで優先度を下げて処理を行います。
ただし、ionice コマンドには落とし穴があります。詳しくは以下のスライドをご覧ください。
参考:
- ionice が効く条件をざっくりと説明したスライド
- ionice 効かなくなる仕組みをざっくり説明したスライド
負荷をかけずにファイルを操作するコツ
本題に入ります。どのようにすれば負荷をかけずにファイルを操作すればよいかというと、ズバリ 少しずつゆっくり処理する ことに尽きます。
例えば、1TB のファイル削除を 10 秒で行う場合と 1000 秒かけて行う場合とでは、一度に発生する I/O 要求の数が大きく異なります。もちろん、後者のほうが一度に生じる I/O 要求は少なくて済みますので、実サービスに悪影響を及ぼすことなく巨大なファイル削除を行うことができます。ちなみに、ionice コマンドで低優先度を指定した場合は、I/O スケジューラが I/O 要求の処理順序の入れ替えや保留を行うことで、対象の I/O 要求をゆっくり処理します。
今回は、Linux におけるファイル操作をいくつかのパターンにわけ、それぞれについて具体的な手法を示します。ちなみに、nice, ionice は付与して損することはないのですべてのパターンにおいて利用することをオススメします。
大量のファイルを作成する方法
急がずに sleep しながらやってください 笑
大量のファイルを移動する方法
方法1. スクリプトを書く
- ファイルのリスト取得
- ls 使うなら -f オプションをつけてね
- リストを元に、ファイルパス指定で1つファイルを移動
- sleep
- 2 に戻る
サンプルプログラム
方法2. find && xargs && sleep
- xargs は -n オプションを忘れない
- 付与しない場合に引数の長さが execve(2) の仕様に制限される
- 具体的な値は
getconf ARG_MAX
で取得可能
大量のファイルを削除する方法
方法1. スクリプトを書く
- ファイルのリスト取得
- ls 使うなら -f オプションをつけてね
- PATH指定で1つファイルを削除
- sleep
- 2 に戻る
方法2. find -delete && sleep
- -delete によって削除を行う
- find で 1 ファイル削除するごとに sleep をはさむ
- -print を用いることで、現在どのファイルを削除しているかがわかる
巨大なファイルを作成する方法
- dd
- oflag で同期書き込みを行うフラグを指定すれば、書き込みでも ionice が効くようになる
- bs のサイズを調整することで I/O の粒度が調整できる
- ibs, obs オプションを用いれば、読み込み/書き込みバイト数をそれぞれ別に制御できる
それぞれのフラグの違いについてはまた別の機会に。。
以下の本に詳しく書いてあるのでオススメです。
巨大なファイルを移動する方法
Linux の仕組み上、ファイルを移動する場合はサイズにかかわらずメタ情報の更新のみで済みます。そのため、特に工夫は必要ありません。気の向くままに mv してください。
ただし、パーティションをまたいで移動する場合は注意が必要です。
この場合は、移動先のパーティションに対して新たにファイルを作成する処理が走ります。そのため、パーティションをまたぐ場合は、ゆっくりとファイルをコピーし、そのあとに元のファイルを削除しましょう。ファイルコピーをゆっくり行う場合には、scp, rsync や pv コマンドなどを用いるとよいかと思います。tar コマンドなどを組み合わせたい場合は、pv コマンドがオススメです。
ゆっくりコピーするコマンドの一例
巨大なファイルを削除する方法
このケースが一番悩まされました。しかし、最近 truncate コマンド使えばいいのでは〜ということに気がつきました。
- truncate コマンドを用いて少しずつファイルサイズを減らす
- sleep をはさむ
- ファイルのサイズを n Byte 小さくする
- n 秒 sleep
- 1 に戻る
サンプルプログラム
まとめ
- 調整の鬼になって停止メンテナンス権を獲得し、豪快にファイルを操作したい人生だった
- 人生甘くないのでゆっくりファイルを消す方法くらいは体得しておいて損はないと思う
- ワンライナーはうっかりミスしやすいのでスクリプトをしっかり書くことを推奨します
- 例示したプログラムやコマンドの品質は保証しませんのでご了承ください