ファイルシステムキャッシュとダイレクトI/O
概要
次のコマンドをご覧ください。
% cp hoge.txt hogehoge.txt
このコマンドを実行した後、次のコマンドを実行します。
% cp hoge.txt hogehogehoge.txt
どちらが高速なのか、それは後者です。という話をしてからMySQLのダイレクトI/Oについて少々書きます。
ファイルシステムキャッシュ
前述の話ですが、単純に順番の問題です。cpコマンドは内部でread()のような参照メソッドを使用しているのですが、これらはファイルシステムキャッシュ(メモリ)にデータがあればそちらを読み込み、無ければファイル(ディスク)から読み込むという処理を行います。
参考までにメモリとHDDのアクセス時間などは次のように1000倍ほど差があります。
CPUのアクセス時間 | 0.0000000010 秒 | 10ns |
メモリのアクセス時間 | 0.0000000060 秒 | 60ns |
HDDのアクセス時間 | 0.0000050000 秒 | 5ms |
SSDのアクセス時間 | 0.0000005000 秒 | 0.5ms |
メモリがたくさん積んであるマシーンであればあるほどファイルへのアクセスを軽減できます。
RDMBSのバッファプール
innodb_buffer_pool_sizeのようにRDBMS側にもファイルへのアクセスを軽減するための機構が存在します。これはファイルシステムキャッシュがあれば不要なのか?
DB専用サーバーとして、よりよい結果を求めるのであればRDBMS側のキャッシュ機構を使うほうが良いと思います。
理由としてはLinuxカーネルではこれらの処理はシステムコールを用いて実装されているのでそれらがオーバーヘッドになるようです。MySQLはC言語なので内部ではシステムコールをwrapして効率的に使えるライブラリ関数を使っているとかそういう理由なのかと勝手に思い込んでいます。
そのほかにもファイルシステムキャッシュは汎用的なのに対してinnodb_buffer_pool_sizeなどは用途が定まっているので効率の面で有利らしい。
ダイレクトI/O
ファイルシステムキャッシュとRDBMSのバッファプールはどちらも実メモリを消費します。話を抽象化すると、メモリは10個のデータを格納できるんですが、ファイルシステムが5個データをキャッシュして、RDMBSのバッファプールが同じデータを5個キャッシュするという事もありえます。
明示的にRDMBSのバッファプールだけが10個データをキャッシュしたいので、MySQL側でダイレクトI/Oを採用します。InnoDBの設定に次のような項目を足す事で実現できます。
innodb_flush_method=O_DIRECT
この結果ファイルシステムキャッシュがほとんど使われなくなるので実メモリの大半をmysqldプロセスのために使えるようになります。64bitで実メモリが8GBのサーバーを使っているのであれば5GB程度のメモリを割り当てる事が可能になります。
バッファプールを多く割り当てる事ができていればmysqldのプロセスが大きくなると思います。もし想定しているよりもプロセスが小さいままだった場合はダイレクトI/Oを使えばもっとプロセスが大きくなる、やも。