Kafka の勉強 (1日目)

Kafka のドキュメント を読みながらわかったことをメモしていく。

設計に興味があるので 4. Design から読む。

4.1 Motivation

以下のような性質を持つデータハンドリングプラットフォームが欲しい。

  • 高いスループット
  • 低いレイテンシ
  • partitioned, distributed, real-time processing
  • fault-tolerance

4.2 Persistence

Don't fear the filesystem

Kafka はメッセージを保存するためにファイルシステムをヘビィに使っている。 多くの人が「ディスクは遅い」と思っているが、適切にディスク上の構造を設計すればネットワークと同じぐらい速くできる。 実際、6台の 7200rpm SATA からなる RAID-5 アレイに対するシーケンシャル書き込み速度は 600MB/sec ぐらいになる。

また、最近の OS はメインメモリをディスクキャッシュに積極的に利用するようになってきている。 モダンな OS であれば、空きメモリ全てをディスクキャッシュとして利用できる。 アプリケーションがもし独自にキャッシュ機構を持つならば、(Direct I/O などでファイルキャッシュを迂回しない限り) 2重にキャッシュを保持することになってしまう。

さらに、Java アプリケーションの場合、

  • Java のオブジェクトのメモリオーバーヘッドはとても大きく、データサイズは2倍以上になる。
  • Javaガーベジコレクションはヒープ内のデータが増えるにつれて遅くなっていく。

という問題もある。

ゆえに、ファイルシステムとページキャッシュを利用する戦略は、インメモリキャッシュを利用する戦略に対して優っている。

さらに、以下のような利点もある。

  • ページキャッシュはサービスが再起動しても消えない。一方、インメモリキャッシュは消えるので、ファイルから再構築するか、完全に空の状態からスタートする必要がある。
  • キャッシュとファイルシステムの間の一貫性をより簡単に担保できる。

したがって、「データをメモリにできるだけためて、空きメモリがなくなったらディスクにフラッシュする」のではなく、「全てのデータを受け取ったら直ちに fsync なしでファイルシステムに書き込む」という設計にした。fsync をしない書き込みは、実質的にはカーネルのページキャッシュへの転送を意味する。

所感

最初 Kafka がインメモリキャッシュを使わずにファイルキャッシュを利用する設計になっているということを聞いたときは、そのほうが実装が楽なのかなぁという程度に思っていたけど、実はインメモリキャッシュよりもファイルキャッシュのほうが優れているという考察の下でこの設計を行ったと知って驚いた。 確かに、ネットワークと同程度のスループットが出ればボトルネックにはならないわけだから、RAID で束ねれば 10Gbps ぐらいのネットワークならば戦えると。ただし、シーケンシャルアクセスが前提となっているので、topic 数とか partition 数が増えてくると(ランダムアクセスに近づくので)辛そう。

あと、fsync しない設計なので、突然の電源断とかがあると直近のメッセージは失われることになる。これは分散しているから別のノードから取ってくればリカバーできるよということだろうか。落雷でデータセンターごと停電とかしたら嫌だな…。UPS に祈りをささげておかないと。