Más contenido relacionado
La actualidad más candente (20)
Similar a ストリームデータ分散処理基盤Storm (20)
Más de NTT DATA OSS Professional Services (20)
ストリームデータ分散処理基盤Storm
- 1. Copyright © 2013 NTT DATA Corporation
NTT DATA Corporation
Masatake Iwasaki
ストリームデータ分散処理基盤 「Storm」
2012年12月10日
NTTデータ オープンソースDAY 2012 講演資料
- 2. 2Copyright © 2012NTT DATA Corporation
Index
1 はじめに
2 Stormとは
3 ストリームデータ処理
4 並列分散フレームワーク
5 サーバ構成と耐障害性
6 プロセス構成と並行性
7 アプリケーション開発
8 まとめ
- 4. 4Copyright © 2013 NTT DATA Corporation
自己紹介
岩崎 正剛(いわさき まさたけ)
株式会社NTTデータ 基盤システム事業本部
OSSプロフェッショナルサービス
HadoopをはじめとするOSS(オープンソースソフトウエア)製品
の技術開発、調査検証、コンサルテーション、サポート、構築支
援などに従事。PostgreSQLの全文検索ツール「Ludia」の開発
をはじめとして、Hadoop以外のOSSも幅広く扱う。
http://oss.nttdata.co.jp/hadoop/
- 5. 5Copyright © 2013 NTT DATA Corporation
今日の内容
Stormの紹介
技術的な話が中心
Hadoopをある程度知っていることを期待
- 6. 6Copyright © 2013 NTT DATA Corporation
Stormの特徴
スケールアウトする分散処理基盤
ストリーミングデータ処理に特化
リアルタイムでインクリメンタルなデータ処理
Hadoopに似ている
Hadoopよりシンプル
SPOFがない
MapReduceより柔軟な計算トポロジ
- 8. 8Copyright © 2013 NTT DATA Corporation
Storm
ストリームデータ分散処理基盤
並列分散処理のためのフレームワーク
「リアルタイム処理のHadoop」?
Similar to how Hadoop provides a set of general
primitives for doing batch processing, Storm provides a
set of general primitives for doing realtime computation.
https://github.com/nathanmarz/storm/
- 9. 9Copyright © 2013 NTT DATA Corporation
Hadoopとの併用
補完する関係にある。
Hadoop
very easy to sort/join/pivot large sets of data
and requires very little work to do so. Does not
address any real-time needs.
Storm
similar paradigm, but very easy to do real-time
https://groups.google.com/forum/?fromgroups=#!topic/storm-user/4it768NTvwA
- 10. 10Copyright © 2013 NTT DATA Corporation
Stormの開発者
Nathan Marz氏
Twitter社(に買収されたBackType社)のエンジニア
Twitterデータを分析するサービスを提供していた
(=> 2013年3月に会社を設立)
https://github.com/nathanmarz
http://manning.com/marz/
- 12. 12Copyright © 2013 NTT DATA Corporation
Stormの利用事例
https://github.com/nathanmarz/storm/wiki/Powered-By
Groupon データ結合、クレンジング、正規化
The Weather Channel 気象データサービス: データ整形、DB格納
FullContact
ソーシャルデータサービス:
外部サービスとのアドレスデータ同期
グラフ解析
Twitter
パートナー向け解析データ提供:
Tweetデータ処理、クリックデータ集計
Infochimps データ収集/配信サービス: ETL
Ooyala
動画サービス:
視聴データ解析、レコメンデーション
spider.io インターネットトラフィック解析: 不正検出
GumGum 広告プラットフォーム: イベント処理
- 14. 14Copyright © 2013 NTT DATA Corporation
ストリームデータとはなにか?
ストリーム的なデータ
連続的に入力される
データ量が時間的に一定しない
保存しきれないほどの量がある
例: Tweetデータ、センサデータ
ストリーム的に処理
データを溜めずインクリメンタルに集計/抽出/加工
- 15. 15Copyright © 2013 NTT DATA Corporation
Hadoopのストリームデータ処理
入力データを分散ファイルシステムに溜めて処理
溜めるためのプロダクトが存在
Flume, Scribe, Fluentd...
バッチ処理
短いバッチジョブの繰り返し
- 16. 16Copyright © 2013 NTT DATA Corporation
Stormのストリームデータ処理
入力データを溜めずに処理
MQを利用する場合が多い
Kafka, Kestrel, RabbitMQ...
イベントドリブン処理
常駐ジョブが入力データをインクリメンタルに処理
- 18. 18Copyright © 2013 NTT DATA Corporation
フレームワークとはなにか?
「枠組み」
特定のロジックに従うプログラムの開発/実行基盤
ライブラリ: ユーザがライブラリを呼ぶ
フレームワーク: フレームワークがユーザロジックを呼ぶ
型にはめることで共通のパーツが使える
型にはめることで変なことをさせない
- 19. 19Copyright © 2013 NTT DATA Corporation
なぜ並列分散処理のフレームワークが必要なのか
並列分散処理のプログラムは書くのが難しい
ノード間でのデータ交換と同期
スケーリング
エラー処理
並列分散処理のプログラムは動かすのが面倒
プログラムとデータの配布、起動と結果の回収
エラー時にゴミとして残ったプロセスとデータの消去
並列分散処理のプログラムは網羅的なテストができない
状況を分散環境で再現すること事態が困難な場合も
- 20. 20Copyright © 2013 NTT DATA Corporation
HadoopのMapReduceの処理の流れ
入力データをタスクに分割
入出力はKeyValueの形式で扱う
Mapは出力をKeyで仕分けてReduceに渡す
データをすべて処理したらジョブは完了
Mapper
Mapper
Mapper
in out
Reducer
Reducer
Reducer
行番号: テキスト
"foo": 3
単語: 1
(単語に分解)
単語: カウント
(単語ごとに集計)
"foo": 1
"bar": 4
"baz": 2
"foo";: 3
"bar": 4
"baz": 2
1000: “foo bar bar”
...
2000: “bar bar baz”
...
3000: “foo foo baz”
...
"bar": 1
"bar": 1
"baz": 1
"foo": 1
"baz": 1
"bar": 1
"bar": 1
"foo": 1
- 21. 21Copyright © 2013 NTT DATA Corporation
MapReduceのフレームワーク
ユーザはMapperとReducerを実装する
MapperとReducerはフレームワークが呼び出す
そこ以外はフレームワークが世話してくれる
プログラムとデータの受け渡し
状態の監視
エラー時のリトライ
public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
protected void map(KEYIN key, VALUEIN value,
Context context) throws IOException, InterruptedException {
public class Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
protected void reduce(KEYIN key, Iterable<VALUEIN> values, Context context
) throws IOException, InterruptedException {
- 22. 22Copyright © 2013 NTT DATA Corporation
枠組みとしてのMapReduce
縛ることでスケーラビリティと開発容易性を保つ
ユーザはロジックとデータの流れの枠組みを変えられない
一見厳しい制限にみえる
各タスクは他の部分と独立に処理
Map -> Reduceの一方通行
でも意外といろいろなことができる
MapReduceの組みあわせと繰り返し
- 23. 23Copyright © 2013 NTT DATA Corporation
低レイテンシな並列分散処理の背景
MapReduceの繰り返しは効率が悪い
何もせず終了するジョブでも1つ数十秒
MapReduceジョブ間のデータ受け渡しがHDFSを経由
MapReduceとは異なるフレームワークがでてきた
グラフ処理: Giraph
分散クエリ: Impala
HadoopプロジェクトもYARNを開発
ノード管理部分とアプリケーション管理部分を分離
MapReduce以外へも汎用化
- 24. 24Copyright © 2013 NTT DATA Corporation
Stormの処理の流れ
Spoutは入力データを後続のBoltに流す
Boltは入力がきたら随時イベントドリブンで処理
HadoopのJob: 与えられたデータセットを処理するバッチ処理
StormのTopology: 常駐してイベントドリブン的にデータを処理
Bolt A
Bolt A
Bolt A
Bolt B
Bolt B
Bolt B
行単位に入力
foo: 3
単語に分割 単語ごとの集計
"foo"
bar: 4
baz: 2
{foo: 3,
bar: 4,
baz: 2}
集約
“foo bar bar”
“bar bar baz”
“foo foo baz”
"bar"
"bar"
"baz"
"foo"
"baz"
Spout Bolt C
"bar"
"foo"
"bar"
- 25. 25Copyright © 2013 NTT DATA Corporation
Stormの計算トポロジ
MapReduceよりも自由度が高い
BoltとSpoutの組み合わせの定義はTopologyと呼ばれる
入出力はアプリケーション次第
Bolt A
Bolt A
Bolt C
Bolt C
Bolt B
Spout A
Bolt D
Spout B
Spout B
Bolt C
- 26. 26Copyright © 2013 NTT DATA Corporation
データ入出力
データ入力
MQからデータを取り込むのが定番
スケールアウト可能な製品が好ましい
Kestrel, Apache Kafka, RabbitMQ...
データ出力
ストリームとして下流に流す
集計結果を永続化
KVS, RDBMS, ...
- 27. 27Copyright © 2013 NTT DATA Corporation
Stormのフレームワーク
ユーザはSpoutとBoltを実装する
Spoutは無限ループで呼ばれ続け、Tupleを流す
BoltはTupleを受け取ったらexecuteを呼び出す
public interface ISpout extends Serializable {
void nextTuple();
public interface IBolt extends Serializable {
void execute(Tuple input);
- 28. 28Copyright © 2013 NTT DATA Corporation
Stormノード間のデータ受け渡し
Tupleと呼ばれるデータ構造であつかう
フィールド名の付いた値の組
public interface Tuple {
public int size();
public int fieldIndex(String field);
public boolean contains(String field);
public Object getValue(int i);
public String getString(int i);
public Integer getInteger(int i);
public Long getLong(int i);
public Boolean getBoolean(int i);
...
public Object getValueByField(String field);
public String getStringByField(String field);
public Integer getIntegerByField(String field);
public Long getLongByField(String field);
public Boolean getBooleanByField(String field);
...
public List<Object> getValues();
public List<Object> select(Fields selector);
...
- 29. 29Copyright © 2013 NTT DATA Corporation
Stormノード間のデータ受け渡し
後続のBoltにTupleを渡す
public class Values extends ArrayList<Object>{
public Values() {
}
public Values(Object... vals) {
super(vals.length);
for(Object o: vals) {
add(o);
}
}
}
collector.emit(new Values("foobar", 3, 0.2));
Tupleの実体は単に値の組
- 30. 30Copyright © 2013 NTT DATA Corporation
グルーピング
Tupleをどの後続Boltに渡すかを決めるロジック
同じデータを複数のBoltに渡すこともできる
FIELDS: 指定されたフィールドのハッシュ値で振り分け
SHUFFLE: ランダムに振り分け
ALL: すべてのBolt同じTupleを送信
DIRECT: 振り分け先のタスクIDを明示的に指定
CUSTOM: 振り分けロジックをユーザが実装
Bolt A
Bolt B
Bolt B
- 32. 32Copyright © 2013 NTT DATA Corporation
Master
Slave
TaskTracker
DataNode
Master
NameNode
Slave
TaskTracker
DataNode
JobTracker
Slave
TaskTracker
DataNode
マスタースレーブ
MapReduceとHDFSの同居がポイント
データ保持ノードにタスクを渡すことで効率的にI/Oを分散
Hadoopのサーバ構成
- 33. 33Copyright © 2013 NTT DATA Corporation
Slave
Master
Stormのサーバ構成
Slave
Supervisor
Slave
Supervisor
Nimbus
Supervisor
ZooKeeper
ZooKeeper
ZooKeeper
マスタースレーブ
状態管理にZooKeeperクラスタを利用
- 34. 34Copyright © 2013 NTT DATA Corporation
ZooKeeper
分散システム開発のためのパーツ
小さな分散ファイルシステム
ディレクトリとファイルの区別がない
open/closeもread/writeもない
設定や状態情報を冗長化して保存
ロック、キュー、カウンタとしても
ノード間のコーディネーション
ファイルの読み書きの際にWatcherを登録
ファイルに変化があるとコールバック
- 35. 35Copyright © 2013 NTT DATA Corporation
Hadoopの対障害性
データブロックのレプリカを複数ノードが持つ
スレーブノードがダウンしたら別ノードでタスクをリトライ
Slave
DataNode
TaskTracker
data block
Task
Slave
DataNode
TaskTracker
data block
Task
Slave
DataNode
TaskTracker
Master
NameNode
Master
JobTracker
- 36. 36Copyright © 2013 NTT DATA Corporation
Master
Slave
TaskTracker
DataNode
Master
NameNode
Slave
TaskTracker
DataNode
JobTracker
Slave
TaskTracker
DataNode
マスターがSPOF(だった)
巨大で重要な管理情報をマスターが(メモリ上に)保持
HadoopのSPOF
ファイルシステムメタデータ登録ジョブと実行状態
- 37. 37Copyright © 2013 NTT DATA Corporation
Slave
Master
StormのSPOF
Slave
Supervisor
Slave
Supervisor
Nimbus
Supervisor
ZooKeeper
ZooKeeper
ZooKeeper
SPOFなし
情報は冗長性のあるZooKeeperクラスタ上に保存
Hadoopと違い管理情報が小さくてすむため
トポロジと割り当て状態
- 38. 38Copyright © 2013 NTT DATA Corporation
Slave
Master
Stormのマスター障害
Slave
Supervisor
Slave
Supervisor
Nimbus
Supervisor
ZooKeeper
ZooKeeper
ZooKeeper
マスターがいなくてもTopologyは動きつづける
単に再起動すればよい
マスターダウン中はタスクの(再)割り当てはできない
- 39. 39Copyright © 2013 NTT DATA Corporation
Slave
Master
Stormのスレーブ障害
Slave
Supervisor
Slave
Supervisor
Nimbus
Supervisor
スレーブマシンまたはSupervisorプロセスのクラッシュ
マスターがスレーブを監視し、タスクを別のノードに移動
Task
Task
ZooKeeper
ZooKeeper
ZooKeeper
- 40. 40Copyright © 2013 NTT DATA Corporation
Slave
Master
Stormのアプリケーションプロセス障害
Slave
Supervisor
Slave
Supervisor
Nimbus
Supervisor
SupervisorがWorkerプロセスを監視して再起動
ZooKeeper
ZooKeeper
ZooKeeper
Worker
Worker
- 41. 41Copyright © 2013 NTT DATA Corporation
Ackを利用したエラー処理
SpoutからTupleを流す際にIDを与えておく
public interface ISpoutOutputCollector {
List<Integer> emit(String streamId,
List<Object> tuple,
Object messageId);
public interface ISpout extends Serializable {
void ack(Object msgId);
void fail(Object msgId);
下流のBoltがack/failを呼ぶと、Spoutに伝わる
Spout BoltMQ
1: キューからデータ取り出し 2: Tupleを流して処理
3: 処理が完了したらack
失敗したらfail
4: ackならキューからの消去をcommit
failならキャンセルしてデータを戻す
- 42. 42Copyright © 2013 NTT DATA Corporation
ノード間通信とZeroMQ
スレーブ間の通信はWorker単位で管理
通信レイヤでの再送や再接続の管理にZeroMQを利用
Disrupter(後述)導入後はバッファリングなしの設定に
将来的には使わなくなる?
https://github.com/nathanmarz/storm/issues/372
- 43. 43Copyright © 2013 NTT DATA Corporation
並列分散処理における対障害性の考えかた
並列分散処理ではエラーは例外的な状況ではない
落ちないプログラムではなく、落ちても平気なプログラム
フレームワークがかなり面倒をみてくれる
でも、アプリケーション側でも意識が必要
無限リトライに陥らない
一部のエラーで全体を無駄にしない
- 45. 45Copyright © 2013 NTT DATA Corporation
Hadoopアプリケーションのプロセス構成
TaskTrackerがスロット数までChildプロセスを起動
スロット数はCPUコア数を目安に設定
適切な並列度はディスクI/Oにもよる
Childプロセスがタスク(Map/Reduce)を処理
Slave
TaskTracker(プロセス)
Child(プロセス)
Task
Child(プロセス)
Task
- 46. 46Copyright © 2013 NTT DATA Corporation
Stormアプリケーションのプロセス構成
Supervisorがスロット数までWorkerプロセスを起動
WorkerはExecutorスレッドを起動
Executorスレッドがタスク(BoltやSpout)を処理
Task数 > Executor数にすることも可能
Slave
Supervisor(プロセス)
Worker(プロセス) Worker(プロセス)
Executor(スレッド)
Task
Task
Executor(スレッド)
Executor(スレッド)
Task
Task
- 47. 47Copyright © 2013 NTT DATA Corporation
非同期処理とDisruptor
処理スレッドと通信スレッドの間をキューで非同期化
同じWorker内で動くタスク同士のやり取りにも
キューとしてLMAX Disruptorを利用
http://lmax-exchange.github.com/disruptor/
以前はプロセス内のやりとりにもZeroMQを利用していた
性能上重要な部分
Worker
Executor
Receive
Thread
Transfer
Thread
Disruptor
Queue
Disruptor
Queue
ExecutorDisruptor
Queue
- 48. 48Copyright © 2013 NTT DATA Corporation
サーバの実装
StormはJavaとClojureで実装されている
プリミティブなデータ型やインタフェースはJavaで定義
Clojureでサーバプロセスを組み上げる
Clojure
LISP系の言語
JVM言語
マルチスレッドプログラミング向きのパーツを提供
- 50. 50Copyright © 2013 NTT DATA Corporation
Javaで記述したHadoopアプリケーション
Mapperの定義
Job job = new Job(new Configuration(), "word count");
job.setJarByClass(WordCount.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
job.submit();
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
Jobの定義と起動
- 51. 51Copyright © 2013 NTT DATA Corporation
Javaで記述したStormアプリケーション
Boltの定義
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("spout", new RandomSentenceSpout(), 5);
builder.setBolt("split", new SplitSentence(), 8)
.shuffleGrouping("spout");
builder.setBolt("count", new WordCount(), 12)
.fieldsGrouping("split", new Fields("word"));
Config conf = new Config();
conf.setNumWorkers(3);
StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
public static class WordCount extends BaseBasicBolt {
Map<String, Integer> counts = new HashMap<String, Integer>();
public void execute(Tuple tuple, BasicOutputCollector collector) {
String word = tuple.getString(0);
Integer count = counts.get(word);
if(count==null) count = 0;
count++;
counts.put(word, count);
collector.emit(new Values(word, count));
}
Topologyの定義と起動
- 52. 52Copyright © 2013 NTT DATA Corporation
並列分散処理フレームワークにおけるDSL
MapとReduceを書くだけだから開発は簡単だといったな
=>あれは嘘だ
現実には数多くのMapperやReducerを作って組み合わせ
それなりにめんどうくさい
DSL(Domain Specific Language)がよく利用される
HadoopではHiveやPigが代表例
特定の問題に特化した抽象度の高いプログラミング言語
C、Java、Rubyといった汎用言語で実装される
アプリケーション開発の生産性向上のためのツール
- 53. 53Copyright © 2013 NTT DATA Corporation
Trident
典型的なパターンのTopologyを実装するためのAPI
射影、結合、集約、分岐、フィルタ、トランザクション
Spout/Operation/Partitionの3種のノードでグラフ構造を定義
FluentスタイルのAPI呼び出しでアプリケーションを記述
(内部DSLに分類される)
TridentTopology topology = new TridentTopology();
TridentState wordCounts =
topology.newStream("spout1", spout)
.parallelismHint(16)
.each(new Fields("sentence"), new Split(), new Fields("word"))
.groupBy(new Fields("word"))
.persistentAggregate(new MemoryMapState.Factory(),
new Count(),
new Fields("count"))
.parallelismHint(16);
- 54. 54Copyright © 2013 NTT DATA Corporation
Clojure DSL
コードをClojureで簡潔に記述できる内部DSL
Clojureのマクロで実装
Clojureで書く利点
Clojureの機能が使える
パターンマッチング、リスト内包表記、遅延評価、マクロ…
並行処理用のパーツはSpoutやBoltでは出番が少なそう
DSL的な何かを作ることに定評のあるLISP系言語
=>恩恵を受けるのはエンドユーザよりも周辺ツール開発者?
- 55. 55Copyright © 2013 NTT DATA Corporation
Clojure DSLで記述したStormアプリケーション
Boltの定義
(defn -main
([name]
(StormSubmitter/submitTopology
name
{TOPOLOGY-WORKERS 3}
(topology
{"spout" (spout-spec sentence-spout :p 5)}
{"split" (bolt-spec {"spout" :shuffle } split-sentence :p 8)
"count" (bolt-spec {"split" ["word"]} word-count:p 12)}
)))))
(defbolt word-count ["word" "count"] {:prepare true}
[conf context collector]
(let [counts (atom {})]
(bolt
(execute [tuple]
(let [word (.getString tuple 0)]
(swap! counts (partial merge-with +) {word 1})
(emit-bolt! collector [word (@counts word)] :anchor tuple)
(ack! collector tuple)
)))))
Topologyの定義と起動
- 56. 56Copyright © 2013 NTT DATA Corporation
DSLの特徴
内部DSL: (Clojure DSL、Tridentはこちら)
母体の言語の枠組み上で動く
構文上の工夫などで独自言語風にみせる
呼び出し方に独自ルールにあるライブラリ?
外部DSL: (Hive、Pigはこちら)
独自の言語処理系を実装
構文解析して構文木をつくり実行
自由な構文が定義できる反面:
エディタ、デバッガといった開発ツールがない
任意のロジックを記述できない(または煩雑)
- 57. 57Copyright © 2013 NTT DATA Corporation
ShellBolt
Boltを外部コマンドとして起動
標準入出力経由のデータ受け渡しで制御
Hadoop Streamingと同じ
任意のプログラミング言語でアプリケーションが書ける
{"command": "next"}
{
"command": "emit",
"id": "12345",
"stream": "1",
"task": 3,
"tuple": ["foobar", 3, 0.2]
}
子プロセスに渡すコマンドの例:
子プロセスからの返却値の例:
- 58. 58Copyright © 2013 NTT DATA Corporation
ローカル環境でのTopologyの実行
分散環境
StormSubmitter.submitTopology("word-count",
conf,
builder.createTopology());
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("word-count",
conf,
builder.createTopology());
ローカル実行
- 60. 60Copyright © 2013 NTT DATA Corporation
Stormのよいところ
スケール可能な並列分散処理フレームワーク
Hadoopができないストリームデータの逐次処理をカバー
対障害性が高い
コードベースがコンパクトでシンプル
特に巨大なHadoopのコードベースと比較して
Clojureによる実装
読んで楽しい(人による)
- 61. 61Copyright © 2013 NTT DATA Corporation
大規模データ処理の広がり
大規模データ処理にHadoopは広く普及した
並列分散処理の開発と運用が実用的に
並列分散処理におけるフレームワークの重要性
汎用のパーツを再利用
複雑さを抑えて(普通の)人間に把握可能に
Hadoop(MapReduce)以外の選択肢も増えてきた
解決すべき問題に応じて使い分け