Think Distributed

Database and Distributed Systems

Reading: Linuxシステムプログラミング

I/O に関係する部分だけ読みました。以下感想などを徒然と。

2 章 ファイルI/O

API の使い方を説明しているだけなので、すでに libc のファイル I/O について知っていたら読み飛ばして問題ないです。唯一知らなかったのは ungetc を複数回呼んだ時の挙動は実装依存ということぐらいでしょうか。

3 章 I/Oのバッファリング

1 byte、512 bytes, 1024 bytes 毎に I/O して、バッファリングした時としていない時でこれだけ処理時間に違いが出ますよというのが最初に説明されています。で、I/O デバイスはだいたい決まった alignment が存在するから、その alignment を意識して I/O しましょうということが書かれています。

alignment の話の後は、 fopen に始まる、標準ライブラリに付いてくる stream I/O の使い方に終始します。で最終的には「標準I/Oライブラリに対する批判」で、標準ライブラリを使うと

  1. アプリケーションと標準ライブラリのバッファ
  2. 標準ライブラリのバッファとカーネルのメモリ空間

の2箇所で2重コピーが発生してしまうからそこが嫌われることもあるよねという話でしめくくられます。書籍では2重コピーを避けるには独自実装が必要なこともあるという書き方がされていて、個人的にも標準 I/O ライブラリは使わないです。標準 I/O のように FILE 構造体で抽象化されても結局 fsync (file descriptor を要求します)を叩くために fd が必要というのがあります。

4 章 Advanced IO

iovec, mmap, epoll の使い方が説明されています。この辺りはよく触れられる部分なので特筆すべき点ではないでしょう。

その後、「I/OスケジューラとI/O パフォーマンス」という節で deadline, anticipatory, cfq, noop について説明されます。ここが I/O 関係で一番見所ではないでしょうか。日本語で書かれた書籍ではあまり触れられていないように感じます。

各 I/O 戦略は、私の理解では、

  • deadline
    • メインの queue (deadline は read は 500ms, write は 5000ms とのこと)、read 用の FIFO queue, write 用の FIFO queue の3つを使うI/O戦略。メインの queue だけだと公平性が損なわれることがあるので、時々専用の queue から優先的に処理するように動作を切り替えながらI/Oをさばいていく。
  • anticipatory
    • I/O 要求が来た時にすぐに次の I/O 要求に移ってしまうのではなく、同一・連続した領域に対する I/O が来ないかを 5ms (デフォルト)待ってから、I/O が来なかったら別の I/O を処理する、というI/O 戦略。
    • 例えば、特定のファイルの先頭 N バイトを読み込んでから、メモリ上で書き換えて、ファイルに書き戻すような処理で有効。

という感じです。

ちなみに、これらは HDD 向けの I/O スケジューラなので、SSD 全盛の昨今は別の I/O 戦略がデフォルトになっているはずで、実際にはすでに使われていない可能性が高いです。