LinuxのI/O
最近Blogに書くネタが「ファイル」に特化してきてだんだんPerlが関係なくなってきている今日この頃ですが、そんなことは気にせずにLinuxカーネルのI/Oについての覚え書きです。
対象読者
仮想ファイルシステム(VFS)
これらのファイルシステムの操作をVFS経由で操作すると幸せになれるのです。
なぜなら、同じシステムコールで、どんなメディア上のどんなファイルシステムにたいしてもアクセスできるという素晴らしい役割を果たしてくれているからです。
このレイヤーのおかげでアプリケーション側からはファイルディスクリプタに対して「読む」という事を指示するだけで済むのでメディアの種類やファイルシステムの種類を考える必要がありません。
ページキャッシュ
時間的局所性
部長から「A会議室の椅子が何個あるのか数えてきて」と頼まれた新入社員が会議室に行ってきてから部長に「椅子は5個です」と答えた後、すぐに社長から同じ事を聞かれました。
その新入社員はその場で「椅子は5個です」と答えました。会議室へもう一度走る事はしません。
ページキャッシュは「アクセスしたばかり」の、ディスク上のファイルシステムが持つデータを、メモリ上に蓄えておくものです。
ページキャッシュは「ある時点でアクセスされたリソースは、高い確率でその後すぐにアクセスされるであろう」という、時間的局所性(temporal locality)という概念の上に成り立っています。
メモリへデータをキャッシュする最初のアクセスではコストがかかりますが、その後はディスクアクセスによるコスト(特にシーキング)を抑える事ができます。
そしてページキャッシュが増加を続けていくと、メモリの空きが少なくなりますが、この時は使用頻度の低いページから切り詰められます。
これらの操作は透過的に行われるので、開発者がこの動作を意識する必要はありません。
ただし、「今切り詰めてしまうと、もしまた読み込まれた場合にメモリに読み込むからコストがかかる、どうしよう…」という悩ましい問題が発生するので、そうした場合にswapしたほうがよい時もあります*1。
Linuxカーネルではディスクへのスワップとページキャッシュのバランスをとるアルゴリズムが実装されています。
% cat /proc/sys/vm/swappinesss
空間的局所性
新入社員の●林さんには毎日のように「A会議室の椅子の数を数えてきてくれ」「C会議室の椅子を数えてきてちょうだい」といった指令が下されます*2
無精な●林さんは考えました。
(A会議室の椅子数えた後、B,C,D,Eの椅子も数えておけば楽だな…)
いわゆる先読みです。
ページキャッシュにはコストがかかりますが、その後HDDのシーキングに比べると大変楽なのでシーキングしたついでにほかのブロックも読み込みます。
この時、HDDに記録されている情報を逐次的に読み取る事になります(空間的局所性)。
つまりランダムアクセスではなく、シーケンシャルアクセスになります。
ページライトバック
dirty buffer
新入社員の●林さんには毎日のように「A会議室の椅子の数を1個増やしといて」「C会議室の椅子を2個減らしなさい」といった指令が下されます*3
無精な●林さんは考えました。
(増やした、減らしたは手元にメモしておいて、あとでまとめてやれば楽だな…)
いわゆるdirtyバッファです。この時の「手元のメモ」がメモリです。
dirtyバッファではディスクに記録されている情報と、メモリ上で保持されている情報が異なりますのでこのbufferがdirtyとマークされます。
このdirtyバッファはいつかはHDDの情報もメモリ上の情報と同期しないといけません。この動作を「ライトバック」といいます。
ライトバックが発生するのは次のときです。
- 空きメモリが設定値を下回る
- バッファがdirtyになってから設定された時間よりも経過する
ここで心配なのですが、●林さんがメモをなくしてしまったらどうなるのか、という問題が発生します。
実際のところ非常に短い期間で同期が行われていますので、影響があるとすれば停電などで急に電源が落ちた場合ぐらいでしょうか。*4
「高速化なんてどうでもいい、UPS信用できない、絶対に同期して」というやや偏執的な要件の場合は同期I/Oとか使うとかするのかな