「fluentd」と「Storm」の比較について

まず、両者はかなり性質の異なるプロダクトなので、以下の比較は筋違い。
筋違いであることを前提に、ストリームデータ処理プラットフォームとしての両者を比べてみる。

基本情報

fluentd

http://fluentd.org/
今をときめくログコレクター/イベントアグリゲーターRubyで実装されているが軽量高速。
RPC基盤ではなく、その下のレイヤーに位置するプロダクト。

Storm

http://storm-project.net/
分散RPC基盤。ストリームデータ版MapReduceフレームワークJava+Clojureで実装されている。
概要については、下記のスライドがとてもわかりやすかった。
Twitterのリアルタイム分散処理システム「Storm」入門

ストリームデータ処理で何をするのかについて

ストリームデータ処理のニーズについて、自分が理解している範囲での簡単な説明。

典型的なWebアプリケーションのアーキテクチャ、すなわちアプリケーションサーバプロセスがステートレスであり、データの永続化はDBのみが担うタイプのソフトウェアに、上手くおさまってくれないタイプの処理がある。具体的には、

  • リアルタイムランキング
  • リアルタイムトレンド分析
  • リアルタイム不正監視

といったもの。

「ランキング?Redisでいいじゃない」Redisお手軽でいいですね。ただ「直近の60分間を対象にしたユニークアクセスランキング」みたいなことをしようとすると、Redisでは難しいかもしれない (時間窓を徐々にずらしていく必要があるし...)
(=> こんなfluentdプラグインを書いた: http://d.hatena.ne.jp/kazuk_i/20130506)

「トレンド分析」これはTwitterの"Worldwide Trends"機能みたいなもので、今一番ホットなハッシュタグをリアルタイムで教えてくれたりするもの。まぁ、これもRedisで事足りる... ただしトレンドを判定するアルゴリズムが、Redisが持つデータ構造で表現できるほどに、十分単純である必要がありそう(単位時間あたりのヒット数でソートした上位アイテム、とか)。

「不正監視」たとえばパスワードのbrute force アタックを防ぎたいとか、botによるサイトクロールを一定の制限を設けて遮断したいなど。過去ののアクセスパターンと直近のアクセスを組み合わせて総合的に判断する必要あり。これはRedisとかではちょっと難しそう。

つまり、状態変化が過去の入力の複雑な重ね合わせとして導かれるようなモデルは、RDBMSや各種KVS、Redisなどに載せるのが難しい。無理に載せると、アップデートのたびに大量のREADクエリを走らせることになってしまい、現実的なパフォーマンスが出ない。

ではどうするか。必要なデータをアプリケーションプロセス内部に、インメモリで保持する。
これと親和性が高そうなのが、ストリームデータ処理であり、イベントドリブンなアーキテクチャであり、そのためのプラットフォームとして世に登場したのが、例えばApache S4であったり、Twitter Stormであったりするわけで、中でもStormが一番モテている印象がある。

ストリームデータを逐次処理するという手法は、金融系のシステム等では随分前からお馴染みのアプローチだったらしい(不正監視とか)。Web業界では、ここ3−4年でマンモスサイト(TwitterとかFacebookとか)への導入が進み、そして、ここ1−2年で、そういったプロダクト(Stormとか)がオープンソース化されて、我々も気軽に使えるようになった。

Stormのスゴイところ

ある種の(大多数の?)処理が、MapReduceでほぼ無尽蔵にスケールアウトするようになったのと同様に、StormでもSpout+Boltを組み合わせることで、ある種のストリームデータ処理をどこまでもスケールさせることができる。Twitter規模のトラフィックで、トレンドハッシュタグのランキングをリアルタイムに算出するなんて用途にうってつけ。

Stormの欠点

MapReduceはどこまでもスケールする代わりに、計算効率を犠牲にしている面がある。よくある単語数をカウントするサンプルなんかは、やってる処理内容に比べて、そのオーバヘッドが極端に大きい例だと思う(まぁ実際にはネットワークやディスクIOがボトルネックなのであまり問題ではないのかもしれないけど)。同じ事がSpout+Boltモデルにも言える。
これは欠点というより、スケーラビリティを追求した結果であり必然。

fluentdのいいところ

fluentdはあくまで土管なので、Stormのように分散処理基盤を提供してくれるわけではない。しかしfluentdには入出力プラグインAPIが用意されているので、プラグインを書くことで、データフローに対して任意の処理を行うことができる。つまりその気になれば、fluentdに複雑なストリームデータ処理を載せてしまうことができる。
一方で、トランザクションやジョブトラッキング機能が必要である場合、すべて自前で実装することになる。

※fluentdストリームに対し、アドホックにクエリを登録して結果を得るというアイデアが存在した :
fluentd+Esperで動的ストリー ムクエリ
@angostura11さん作のEsper。これはスゴイ!

耐障害性について

これは、「高可用性」と「整合性」の2つに分けて考える必要があると思う。

高可用性について
Storm
高可用性はStormの最大の売りの一つ。Hadoop同様、MasterノードがWorkerにタスク(SpoutやBolt)を動的に割り振る。Workerに障害が発生した場合、タスクは別のWorkerに自動的に引き継がれる。
fluentd
稼働プラグインを動的にデプロイするような仕組みは用意されていない。高可用性を実現するには、同じ設定のWorkerを複数並べて、HA構成にする必要がある?
整合性について
Storm
上で見たように、ストリームデータ処理方式の最大のメリットが、アプリケーションプロセスがデータをインメモリに持たせられることであるとすると、『Stormを採用すれば耐障害性が担保されるので、整合性も保たれる』と考えるのは妥当なのか?例えばStormに標準で付いてくるワードカウントのサンプルプログラム、これの実装を見ると、累計カウント値は Workerスレッド内の、集計担当Boltが保持しているHashMapインスタンスに保存されている。つまり、何らかの障害が発生し、このインスタンスをホストするサーバが吹き飛んでしまえば、(以降の処理は他のWorkerが受け継いでくれるものの)当然新Boltからemitされる値はゼロにリセットされる。これを何とかするには、中間データ(上記例であれば、累計カウント値など)を、Redisのような外部DBにmemoizeしなければならない、、、がそれではパフォーマンスが出ないし、そもそもストリームデータとしてStormで処理する必然性が無い。。。
fluentd
上と同じ事がfluentdでも言える。加えて、fluentdではデータがWorkerで必ず処理されることの保証が無い。

上記のような整合性リスクに関する考え方が、ストリームデータ処理を最も特徴づけるのではないかという気がしている。

自分はどうするか

弊社(CareerLink Vietnam)は業務の性質上、アクセスパターンの可視化やユーザ不正行動監視が重要。ひと月ほど前から段階的に、各種処理をストリームデータ処理として実装しなおしている。
しかし、うちのインフラは規模がかなり小さく(サーバも6台しかないし)、ストリームデータ処理のために何台もノードを割り当てることはできない。Stormの強みが活かせる環境ではない。しばらくはStormを諦めて、fluentdでささやかにストリームデータ処理しようと思っている。なにせ、fluentdならRubyで書けるし。(これが一番大きい)

"fluentd as a Poor-man's Storm"、 どうかなぁ。