JVM上でのストリーム処理エンジンの変遷

406 views
364 views

Published on

2016/05/21 JJUG CCC 2016 Springでの発表資料

Published in: Engineering
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
406
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

JVM上でのストリーム処理エンジンの変遷

  1. 1. JVM上の ストリーム処理エンジンの変遷 2016/05/21 JJUG CCC 2016 Spring 木村宗太郎(@kimutansk) https://www.flickr.com/photos/mattridings/9138233663
  2. 2. 自己紹介 • 木村 宗太郎(Sotaro Kimura) • ビッグデータ界隈に生息する何でも屋 • バックエンドからフロントエンド、技術検証から運用、 ドキュメント書きまで色々 • Scala Matsuri運営スタッフ • 元Storm使い • StormのためだけにClojureを勉強してましたよ・・・ • 現Spark Streaming使い • この発表ではそれ自体にはあまり触れません。 • Twitter他 : @kimutansk 1
  3. 3. アジェンダ 1. ストリーム処理とは? 2. ストリーム処理系プロダクトの変遷 3. どのプロダクトを使うべきか? 4. プロダクト選定時に考えるべきこと 5. サービス開発時に考えるべきこと 6. 実際のストリーム処理の組み方例 2
  4. 4. 3 1. ストリーム処理とは? バッチ処理 対話型クエリ ストリーム処理 実行タイミング 手動起動 定期実行 手動起動 定期実行 常時実行 処理単位 保存済みデータを 一括処理 保存済みデータを 一括処理 1~少数の フローデータを処理 実行時間 分~時間 秒~分 永続実行 データサイズ TBs~PBs GBs~TBs Bs~KBs(1件あたり) 処理時間 分~時間 秒~分 ミリ秒~秒 主な用途 ETL ビジネスレポート生成 機械学習モデリング インタラクティブBI 分析 異常/不正検知 レコメンド 可視化 代表的 OSSプロダクト MapReduce Spark Tez Impala Drill Presto (後述) • ビッグデータの処理モデルは主に3つある。
  5. 5. 4 1. ストリーム処理とは? • バッチ処理 • データストアに蓄積したデータを 一括変換、レポート/モデル生成を行うモデル 生成したデータの出力先は 主にデータストア
  6. 6. 5 1. ストリーム処理とは? • 対話型クエリ • データストアに蓄積したデータに 対してクエリを実行し、結果を取得するモデル クエリの実行結果は実行元 で取得するケースが多い
  7. 7. 6 1. ストリーム処理とは? • ストリーム処理 • 「連続発生データを常時処理し続ける」モデル • データの発生元は多岐にわたる センサー データ ログ アプリ 履歴 データ発生元 メッセージキュー ストリーム処理部 データ利用先
  8. 8. 7 1. ストリーム処理とは? バッチ処理 対話型クエリ ストリーム処理 実行タイミング 手動起動 定期実行 手動起動 定期実行 常時実行 処理単位 保存済みデータを 一括処理 保存済みデータを 一括処理 1~少数の フローデータを処理 実行時間 分~時間 秒~分 永続実行 データサイズ TBs~PBs GBs~TBs Bs~KBs(1件あたり) 処理時間 分~時間 秒~分 ミリ秒~秒 主な用途 ETL ビジネスレポート生成 機械学習モデリング インタラクティブBI 分析 異常/不正検知 レコメンド 可視化 代表的 OSSプロダクト MapReduce Spark Tez Impala Drill Presto (後述) • 今回の対象となるのは「ストリーム処理」
  9. 9. 8 2. ストリーム処理系プロダクトの変遷 • ストリーム処理部を実現するプロダクトを ここでは「ストリーム処理エンジン」と呼ぶ • 元は2011年のStorm公開を機に発展 • 最近多数のプロダクトが公開 • 下記のような派生パターン有 • UIでDataflow定義 • 処理を定義可能なUIを保持するパターン • DSL • 同一の記述で複数のストリーム処理エンジン上で アプリケーションが実行可能
  10. 10. 9 2. ストリーム処理系プロダクトの変遷 古 新公開時期 DSL UIで Dataflow定義 純ストリーム処理エンジン (Heron?) Storm Gearpump Summingbird NiFiSpring Cloud Data Flow Cask Hydrator Beam ここ数年で公開
  11. 11. 10 2. ストリーム処理系プロダクトの変遷 古 新公開時期 DSL UIで Dataflow定義 純ストリーム処理エンジン (Heron?) Storm Gearpump Summingbird NiFiSpring Cloud Data Flow Cask Hydrator Beam ここ数年で公開 最近多くプロダクトが公開 全部は説明できないため、 元祖と、最近のものをいくつか紹介
  12. 12. 2. ストリーム処理系プロダクトの変遷 • Storm • 2011年公開 by Twitter • 実装言語:Clojure • Clojureが読み書き出来ないと深い問題は追えない。 • 広まった初のOSSストリーム処理エンジン • At Least Onceが可能になったのが大きい。 • 初期のプロダクトのため問題も多かった。 • データ取得側の性能が高いとあふれて死ぬ。 • デフォルトのスレッド配置が非効率。 • At Least OnceのAckの処理効率が非効率。 • 以後のストリーム処理プロダクトに大きく影響。 11
  13. 13. 2. ストリーム処理系プロダクトの変遷 • Spark(Spark Streaming) • 2013年公開 by amplab • 実装言語:Scala • バッチ処理フレームワークSpark上で 小バッチを連続実行し、ストリーム処理を実現 • マイクロバッチと呼ばれる。 • スループットは大きいが、レスポンスは遅い。 • Sparkエコシステム上で実行可能なのが大きい。 • 機械学習ライブラリの利用 • SQLによるデータ操作 • 開発手法も同様のものが利用可能 12
  14. 14. 2. ストリーム処理系プロダクトの変遷 • NiFi • 2014年に公開 by NSA(当時はNiagrafiles) • 実装言語:Java • 画面上でデータフローを定義し、 複数サーバにデプロイして実行可能 • HTTPでデータ取得>変換>HDFSに投入 etc… • コンポーネント間のキュー毎に 優先度設定やQoS設定が定義可能 13
  15. 15. 2. ストリーム処理系プロダクトの変遷 14
  16. 16. 2. ストリーム処理系プロダクトの変遷 • Flink • 2014年に公開 • 2011年からStratosphereとして公開 • 実装言語:Scala • バッチ処理とストリーム処理両方のAPIを 提供するストリーム処理エンジン • 障害対応のための状態の自動保存が強力 • 自動的に各コンポーネントの状態を保存 • Exactly Onceを謳っているが、それは後述 • 高レベルAPIと低レベルAPIの両方を提供 • 簡易なものは簡単に組める。 15
  17. 17. 2. ストリーム処理系プロダクトの変遷 • Apex • 2015年に公開 by DataTorrent • 実装言語:Java • 元々金融アプリケーション用プロダクトで 可用性、耐障害性重視の設計 • 運用時の問題切り分けも容易な構成 • メッセージバッファリングで障害発生時の影響を低減 • ただし、その分性能が多少犠牲になっている模様 • NiFiと同じく画面上からDataFlowを定義可能 • スケーラビリティにも優れた構成 • ストリーム処理中にAutoScalingが可能 16
  18. 18. 2. ストリーム処理系プロダクトの変遷 • Gearpump • 2015年に公開 by Intel • 実装言語:Scala • Googleの「MillWheel」に影響を受けたプロダクト • ストリーム処理モデルの論文 • Actorベースの「薄い」構成で拡張性が高い • その分、状態管理なども自前で準備する必要有 • Reactive Streamsに準拠しており、 標準化されたBack Pressure機構を保持 • 独特の記述により直観的にグラフを定義可能 • 後ほど紹介 17
  19. 19. 2. ストリーム処理系プロダクトの変遷 • Beam • 2016年に公開 by Google • 実装言語:Java • バッチ処理/ストリーム処理を抽象化し、 複数の実行エンジン上にデプロイ可能なDSL • Google Cloud Dataflow、Spark、Flinkにデプロイ可能 • つまりはストリーム処理対応版Asakusa Framework • ただ、当然ながら各エンジンの機能を 全て使いこなせるわけではない。 • ポータビリティを確保するか、 機能的、性能的な優位性を求めるかの選択となる。 18
  20. 20. 3. どのプロダクトを使うべきか? • 気になるのは、 『これだけプロダクトが乱立している状況で、 どのプロダクトを使うべきか?』 19
  21. 21. 3. どのプロダクトを使うべきか? • 気になるのは、 『これだけプロダクトが乱立している状況で、 どのプロダクトを使うべきか?』 20 むしろ私が一番教えてほしい 教えてください
  22. 22. 3. どのプロダクトを使うべきか? • と、いうのも・・・ • 様々な比較資料はプロダクトを推進する 企業サイドのものであり、バイアスが大きい • 特に、最近はFlink、Apex陣営の資料が多い。 • 個人的には直近はSpark Streaming 将来的にはFlink、Apex、Gearpumpの3択 • 現時点の最良プロダクトは、すぐ時代遅れ。 • Beamを使えば「大失敗」はまずないとは思われるが、 実行エンジンの機能も引き出し切れない。 • 特に、各エンジンの持つ機械学習等の固有ライブラリへの 対応について不安が大きい。 • と、いうことで・・・ 21
  23. 23. 3. どのプロダクトを使うべきか? • ストリーム処理を構築する上で 考えるべきことについて説明します。 • プロダクト選定時 • サービス開発時 • この項目自体も Storm、Spark Streamingから挙げたものです。 • もしFlink、Apex、Gearpump等他プロダクトの 経験者がいれば、是非とも補足を。 22
  24. 24. 4. プロダクト選定に考えるべきこと • プロダクト選定時に考えるべき主要観点 1. 実装言語は何か? 2. インストールの際に何が必要? 3. Back Pressure機構を有しているか? 4. サービス動作中にどこまで更新可能か? 5. 接続用コンポーネントが揃っているか? 6. 【注意】Exactly Once機能の価値は高くない。 23
  25. 25. 4. プロダクト選定に考えるべきこと 1. 実装言語は何か? • ストリーム処理系プロダクトを扱う場合、 発展途上の状態で使うのが基本となるため。 • 情報は少なく、問題が発生した際に どうしても自分で解析せざるを得なくなる。 • メーリングリストに問い合わせても時間はかかる。 • 問題解析ができるレベルの知識を持った 言語で組まれたプロダクトを使うのがおすすめ。 • 幸い、最近のものはJavaとScalaがメインのため、 あまりこれを気にする機会はないが。 • StormはClojureがコアのため、なかなか酷かった・・・ 24
  26. 26. 4. プロダクト選定に考えるべきこと 2. インストールの際に何が必要? • 必然的に複数のマシンに跨る分散構成となり、 事前に何かをインストールするのが困難なため。 • インストールする=何かのDaemonを起動するため、 クラスタ全域に入れるとリソース的な無駄も大きい。 • まっさらなリソースマネージャの上で そのまま動作することが望ましい。 • ストリーム処理系はHadoopクラスタなどと 同居することも多く、その上でそのまま動くのは大きい。 • YARN、Mesos etc... 25
  27. 27. 4. プロダクト選定に考えるべきこと 3. サービス動作中にどこまで更新可能か? • ストリーム処理は「連続データを常時処理」の 関係上、長期にわたって動き続けるため。 • 一定時間で終了するバッチ処理とは明確に サービス要件が違うので、要注意。 • ApexやGearpumpが動作中の更新機能を保持 26 参照:http://www.slideshare.net/BhupeshChawda1/introduction-to-apache-apex-cods-2016
  28. 28. 4. プロダクト選定に考えるべきこと 3. サービス動作中にどこまで更新可能か? • ストリーム処理は「連続データを常時処理」の 関係上、長期にわたって動き続けるため。 • 一定時間で終了するバッチ処理とは明確に サービス要件が違うので、要注意。 • ApexやGearpumpが動作中の更新機能を保持 27 参照:http://www.gearpump.io/releases/latest/features.html
  29. 29. 4. プロダクト選定に考えるべきこと 4. BackPressure機構を有しているか? • 性能のアンバランスが発生した際に システムのダウンが発生するのを防ぐため。 • ※BackPressureとは? • 上流の方が性能が高い場合に下流で溢れるのを 防止する機構全般。Reactive Streamsとして標準化。 28 100メッセージ/秒 処理 10メッセージ/秒 処理
  30. 30. 4. プロダクト選定に考えるべきこと 4. BackPressure機構を有しているか? • 性能のアンバランスが発生した際に システムのダウンが発生するのを防ぐため。 • ※BackPressureとは? • 上流の方が性能が高い場合に下流で溢れるのを 防止する機構全般。Reactive Streamsとして標準化。 29
  31. 31. 4. プロダクト選定に考えるべきこと 4. BackPressure機構を有しているか? • 性能のアンバランスが発生した際に システムのダウンが発生するのを防ぐため。 • ※BackPressureとは? • 上流の方が性能が高い場合に下流で溢れるのを 防止する機構全般。Reactive Streamsとして標準化。 30
  32. 32. 4. プロダクト選定に考えるべきこと 4. BackPressure機構を有しているか? • 性能のアンバランスが発生した際に システムのダウンが発生するのを防ぐため。 • ※BackPressureとは? • 上流の方が性能が高い場合に下流で溢れるのを 防止する機構全般。Reactive Streamsとして標準化。 31 いずれ溢れて障害発生!
  33. 33. 4. プロダクト選定に考えるべきこと 4. BackPressure機構を有しているか? • 性能のアンバランスが発生した際に システムのダウンが発生するのを防ぐため。 • ※BackPressureとは? • 上流の方が性能が高い場合に下流で溢れるのを 防止する機構全般。Reactive Streamsとして標準化。 32 10メッセージ要求 10メッセージ送信
  34. 34. 4. プロダクト選定に考えるべきこと 5. 接続用コンポーネントが揃っているか? • ストリーム処理エンジンは自前では処理を するのみで、外部とのやり取りが必須なため。 33 センサー データ ログ アプリ 履歴 データ発生元 メッセージキュー ストリーム処理部 データ利用先
  35. 35. 4. プロダクト選定に考えるべきこと 5. 接続用コンポーネントが揃っているか? • ストリーム処理エンジンは自前では処理を するのみで、外部とのやり取りが必須なため。 34 センサー データ ログ アプリ 履歴 データ発生元 メッセージキュー ストリーム処理部 データ利用先 Kafka DistributedLog RabbitMQ MQTT Broker Amazon Kinesis Cloud Pub/Sub Azure Event Hub 各種 データストア
  36. 36. 4. プロダクト選定に考えるべきこと 6. 【注意】Exactly Once機能の価値は高くない。 • ストリーム処理エンジン単体では 外部に対するExactly Onceは実現できないため。 • 外部に対するアクセスと、状態保存が 「Atomic」でないため、障害時、重複処理が発生 35 メッセージを通知して アラーム発報するケースを考える
  37. 37. 4. プロダクト選定に考えるべきこと 6. 【注意】Exactly Once機能の価値は高くない。 • ストリーム処理エンジン単体では 外部に対するExactly Onceは実現できないため。 • 外部に対するアクセスと、状態保存が 「Atomic」でないため、障害時、重複処理が発生 36 通知後、ローカル状態を 更新する前に障害が発生すると・・?
  38. 38. 4. プロダクト選定に考えるべきこと 6. 【注意】Exactly Once機能の価値は高くない。 • ストリーム処理エンジン単体では 外部に対するExactly Onceは実現できないため。 • 外部に対するアクセスと、状態保存が 「Atomic」でないため、障害時、重複処理が発生 37 再度通知が行われ、 重複してアラームが発報される!
  39. 39. 5. サービス開発時に考えるべきこと • サービス開発時に考えるべき主要観点 1. 【必要な場合】Exactly Onceの実現方法 2. データがプロセスをまたがないように配置 3. 極力メモリ上に収めるか、並列度を調整 4. ログを集約する機構を準備 38
  40. 40. 5. サービス開発時に考えるべきこと 1. 【必要な場合】Exactly Onceの実現方法 • 重複しても問題ないようサービスを設計する。 • 「ID」+「時刻」をキーにしてデータストアに保存。 重複処理をはじく。 • 重複して処理しても同一データは複数出力されない。 • 「最後のデータ」の値を使用するようにすることで、 一時的にずれても補正がきくようにする。 • 統計値や、合計値を求めるケースに有効。 • アラーム発報のような場合は上記対処の上で 「データストアから取得して発報」する形にする。 39
  41. 41. 5. サービス開発時に考えるべきこと 2. データがプロセスをまたがないように設定 • プロセスをまたぐことによるオーバーヘッドが ストリーム処理では大きく響くため。 • シリアライズ>プロセス間通信>デシリアライズ • ただ、Groupingなどで最低限は必要になる。 • メッセージのルーティングで、 極力プロセスをまたがないよう設定する。 40
  42. 42. 5. サービス開発時に考えるべきこと • StormWordCountにおいて無駄が多い例 41 TestWord Spout Exclamation Bolt Additional Bolt Worker1 Worker2 Worker3 同一“word” でGrouping RoundRobin方式で配分 プロセス
  43. 43. 5. サービス開発時に考えるべきこと • StormWordCountにおいて無駄を削減した例 42 TestWord Spout Exclamation Bolt Additional Bolt Worker1 Worker2 Worker3 同一“word” でGrouping 同一プロセス内の コンポーネントに流す プロセス
  44. 44. 5. サービス開発時に考えるべきこと 3. 極力メモリ上に収めるか、並列度を調整 • ディスクアクセスを行う同期的処理を行うと、 ストリーム処理側に追いつけなくなるため。 • Redis、Infinispan、Ignite等の メモリ上に収まる系統のプロダクトを用いる。 • ディスクにアクセスが必要な場合、 該当コンポーネントの並列度を上げてしのぐ。 43
  45. 45. 5. サービス開発時に考えるべきこと 4. ログを集約する機構を準備 • 処理が複数ホストに分散する関係上、 エラーがどこで発生したかの把握が困難なため。 • LogAppenderで集約サーバに送信 • fluentd等で集約サーバに集約 • ログ出力先をNFSマウントして出力 44
  46. 46. 6. 実際のストリーム処理の組み方例 • Gearpumpを例にして説明 • Gearpumpのアプリケーションは下記で構成 • 各コンポーネントのコード • コンポーネントを組み合わせてデプロイするコード 45 例:WordCountを行うアプリケーション Split Sum 単語ごとに集約 Sum.scala Split.scala HashPartitioner (既存コンポーネント) WordCount.scala
  47. 47. 6. 実際のストリーム処理の組み方例 • Split.scala 46 class Split(taskContext : TaskContext, conf: UserConfig) extends Task(taskContext, conf) { import taskContext.{output, self} // 1. 自分自身にStartメッセージを通知。 override def onStart(startTime : StartTime) : Unit = { self ! Message("start") } // 2. 文章を単語に分割し、空文字を除去した上で下流に送信 override def onNext(msg : Message) : Unit = { Split.TEXT_TO_SPLIT.lines.foreach { line => line.split("[s]+").filter(_.nonEmpty).foreach { msg => output(new Message(msg, System.currentTimeMillis())) } } // 3. 次メッセージを自分に対して送信するタスクを仕掛ける import scala.concurrent.duration._ taskContext.scheduleOnce(Duration(100, TimeUnit.MILLISECONDS))(self ! Message("continue", System.currentTimeMillis())) } }
  48. 48. 6. 実際のストリーム処理の組み方例 • Sum.scala 47 class Sum (taskContext : TaskContext, conf: UserConfig) extends Task(taskContext, conf) { private[wordcount] val map : mutable.HashMap[String, Long] = new mutable.HashMap[String, Long]() private[wordcount] var wordCount : Long = 0 private var snapShotTime : Long = System.currentTimeMillis() private var snapShotWordCount : Long = 0 private var scheduler : Cancellable = null override def onStart(startTime : StartTime) : Unit = { // 1. 起動時に状態出力タスクを仕掛ける。 scheduler = taskContext.schedule(new FiniteDuration(5, TimeUnit.SECONDS), new FiniteDuration(30, TimeUnit.SECONDS))(reportWordCount) } override def onNext(msg : Message) : Unit = { if (null == msg) { return } // 2. 受信したメッセージから単語を取得し、総受信回数と単語ごとの受信回数をカウント val current = map.getOrElse(msg.msg.asInstanceOf[String], 0L) wordCount += 1 map.put(msg.msg.asInstanceOf[String], current + 1) }
  49. 49. 6. 実際のストリーム処理の組み方例 • WordCount.scala 48 object WordCount extends AkkaApp with ArgumentsParser { private val LOG: Logger = LogUtil.getLogger(getClass) val RUN_FOR_EVER = -1 // 1. 起動時のCLIから読み込む項目と形式、注釈、必須/オプショナル、デフォルト値を定義 override val options: Array[(String, CLIOption[Any])] = Array( "split" -> CLIOption[Int]("<how many split tasks>", required = false, defaultValue = Some(1)), "sum" -> CLIOption[Int]("<how many sum tasks>", required = false, defaultValue = Some(1)) ) def application(config: ParseResult) : StreamApplication = { // 2. CLIから読み込んだ設定項目を用いてProcessorを生成 val splitNum = config.getInt("split") val sumNum = config.getInt("sum") val split = Processor[Split](splitNum) val sum = Processor[Sum](sumNum) // 3. メッセージのProcessor間の割り振りを行うPartitionerを生成 val partitioner = new HashPartitioner // 4. ProcessorとPartitionerを用いてDAGを作成 val app = StreamApplication("wordCount", Graph(split ~ partitioner ~> sum), UserConfig.empty) app } 直観的なグラフの組み方が 可能
  50. 50. まとめ • ビッグデータは主に下記3つの処理モデル 1. バッチ処理 2. 対話的クエリ 3. ストリーム処理 • プロダクトが多く、ベストは選びにくい状況 • プロダクトは異なっても共通点は多い 1. 性能特性/ボトルネックとなるポイント 2. データ設計 3. 解析を行うための準備 etc • 上記とプロダクト成熟度を踏まえ構築 49
  51. 51. Enjoy stream processing! https://www.flickr.com/photos/allan_harris/2422708123

×