Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

Akka stream

4.593 visualizaciones

Publicado el

関数型ストリーム処理勉強会 2015.11.7の発表資料

Publicado en: Software
  • DOWNLOAD FULL BOOKS, INTO AVAILABLE Format, ......................................................................................................................... ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... 1.DOWNLOAD FULL. PDF EBOOK here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... 1.DOWNLOAD FULL. EPUB Ebook here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... 1.DOWNLOAD FULL. doc Ebook here { https://tinyurl.com/y6a5rkg5 } ......................................................................................................................... ......................................................................................................................... ......................................................................................................................... .............. Browse by Genre Available eBooks ......................................................................................................................... Art, Biography, Business, Chick Lit, Children's, Christian, Classics, Comics, Contemporary, Cookbooks, Crime, Ebooks, Fantasy, Fiction, Graphic Novels, Historical Fiction, History, Horror, Humor And Comedy, Manga, Memoir, Music, Mystery, Non Fiction, Paranormal, Philosophy, Poetry, Psychology, Religion, Romance, Science, Science Fiction, Self Help, Suspense, Spirituality, Sports, Thriller, Travel, Young Adult,
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí
  • You provided a really good content, thanks! http://www.chaussureeshop.com/
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí

Akka stream

  1. 1. copyright Fringe81 Co.,Ltd. Akka Stream @mtoyoshi
  2. 2. copyright Fringe81 Co.,Ltd. Amazon Kinesis 1行目 2行目 3行目 4行目 ・ ・ ・ 処理 ・・・ 処理
  3. 3. copyright Fringe81 Co.,Ltd. Amazon Kinesis 1行目 2行目 3行目 4行目 ・ ・ ・ ・・・ Akka Actor で処理
  4. 4. copyright Fringe81 Co.,Ltd. Akka Actor便利ですが ・メッセージ(データ)が型安全でない ・OutOfMemoryに遭遇 ・メッセージ送受信の仕組み、汎用的  
  5. 5. copyright Fringe81 Co.,Ltd. Akka Stream? Typesafeより2015.07に1.0リリース Akka Actor Akka Stream Akka HTTP
  6. 6. copyright Fringe81 Co.,Ltd. Migration Guide 1.0 to 2.0 https://github.com/drewhk/akka/pull/30/files
  7. 7. copyright Fringe81 Co.,Ltd. RxJava Reactive Streams (JEP266) Vert.x Akka Stream ・・・ Slick3 mongoDB a standard for asynchronous stream processing with non-blocking back pressure その他 OSS
  8. 8. copyright Fringe81 Co.,Ltd. 特徴 ・バックプレッシャーによりバッファ溢れの危 険を回避しつつパフォーマンスにも配慮 ・ReactiveStreams規格のものと接続可能 ・ストリームを構成する豊富な部品群 ・部品群の合成性、拡張性 ・ビジュアルなグラフDSL
  9. 9. copyright Fringe81 Co.,Ltd. 特徴 ・API変更はこれからも続く(1.0->2.0) ・複数ノードにまたがった  ストリームの構築は未対応 ・モナってはいない
  10. 10. copyright Fringe81 Co.,Ltd. 今日はOverview的な話 ・Akka Streamの構成要素は? ・どういうふうにプログラミングする? ・バックプレッシャーが特徴みたい  概念レベルの理解から一歩進めたい
  11. 11. copyright Fringe81 Co.,Ltd. 部品群を組み合わせて RunnableGraphを作る ※1つ以上のSourceと1つ以上のSinkが必要
  12. 12. copyright Fringe81 Co.,Ltd. 部品群を組み合わせて RunnableGraphを作る ※1つ以上のSourceと1つ以上のSinkが必要
  13. 13. copyright Fringe81 Co.,Ltd. val source = Source(1 to 10) val filter = Flow[Int].filter(_ % 2 == 0) val map = Flow[Int].map(_ * 2) val sink = Sink.foreach[Int](println) val runnableGraph = source.via(filter).via(map).to(sink) runnableGraph.run() RunnableGraphの構築と実行
  14. 14. copyright Fringe81 Co.,Ltd. Source(1 to 10) .filter(_ % 2 == 0) .map(_ * 2) .runForeach(println) RunnableGraphの構築と実行 こう書くことも出来る val source = Source(1 to 10) val filter = Flow[Int].filter(_ % 2 == 0) val map = Flow[Int].map(_ * 2) val sink = Sink.foreach[Int](println) val runnableGraph =source.via(filter).via(map).to(sink) runnableGraph.run()
  15. 15. copyright Fringe81 Co.,Ltd. Source[Int] - Flow[Int,String] - Sink[String] Source[Int] - Flow[String,Long] Sink[String] Function1のように InとOutの型が合えば合成可能
  16. 16. copyright Fringe81 Co.,Ltd. implicit val system = ActorSystem() implicit val materializer = ActorMaterializer() val source = Source(1 to 10) val filter = Flow[Int].filter(_ % 2 == 0) val map = Flow[Int].map(_ * 2) val sink = Sink.foreach[Int](println) val runnableGraph = source.via(filter).via(map).to(sink) runnableGraph.run() materializer WHAT HOW
  17. 17. copyright Fringe81 Co.,Ltd. 利用可能な処理: map filter collect take / takeWhile drop / dropWhile flatten fold scan grouped / groupBy recover などなど
  18. 18. copyright Fringe81 Co.,Ltd. val future: Future[List[Int]] = ... val src: Source[List[Int], Unit] = Source(future) src.mapConcat(identity).map(_ * 2) def mapConcat[T](f: Out => Iterable[T]) Source[List[Int]]]だとList[Int]が1つ、 ストリームを流れる事になる。 mapConcatを使う事でList要素のIntそれぞれが ストリームを流れるように出来る。
  19. 19. copyright Fringe81 Co.,Ltd. zipWithIndexを使おうと思った。 が、用意されてなかった。 ...作る! case class ZipWithIndex[T]() extends PushStage[T, (T, Int)] { var i = -1 override def onPush(elem: T, ctx: Context[(T, Int)]): SyncDirective = { i += 1 ctx.push((elem, i)) } } Source(List("A", "B", "C")) .transform(() => ZipWithIndex()) .runForeach(println) // (A,0) (B,1) (C, 2)
  20. 20. copyright Fringe81 Co.,Ltd. Source#apply 使用頻度が多そう(?)なもの ・Iterableから ・Iteratorから ・Futureから ・Fileから↓ SynchronousFileSource(new java.io.File("...")) Source[ByteString]が出来る。 ※Akka2.4ベースになればJava7追加の AsynchronousFileChannel等のNIO API使いたいとのこと。
  21. 21. copyright Fringe81 Co.,Ltd. ちょっとハマった IterableからSourceを作ることが出来る // Compile Error val src = Source(Seq(1,2,3)) // Compile Success val src = Source(List(1, 2, 3)) えっ?
  22. 22. copyright Fringe81 Co.,Ltd. ちょっとハマった Iterable とは collection.Immutable.Iterable // Compile Error val src = Source(Seq(1,2,3)) // Compile Success val src = Source(List(1, 2, 3)) Seq は collection.Seq、つまりcollection.Iterable type Seq[+A] = scala.collection.Seq[A] val Seq = scala.collection.Seq scala/package.scala
  23. 23. copyright Fringe81 Co.,Ltd. Source#apply Source(initialDelay=1.second, interval=100.millis, tick="msg") 100ms毎にmsgというStringを下流に永遠に流す Tcp().bind("127.0.0.1", 8888) こういうSourceも作れる TCP connectionを待ち ByteStringをストリームとして処理する Source(Props[MyActor]) Actorはメッセージ受けて 下流になんらかのデータを流していく
  24. 24. copyright Fringe81 Co.,Ltd. val src: Source[String, Cancellable] = Source(initialDelay=0.second, interval=100.millis, tick="msg") val sink: Sink[String, Future[Int]] = Sink.fold[Int, String](0){ case (sum, _) => sum + 1 } src sink 100ms毎に"msg"を送出 msgを受信する度に件数カウント ※foldは上流のデータが完了して集計終了となる Cancellable Future[Int] ストリームの実行者に渡される値 Materialized Value
  25. 25. copyright Fringe81 Co.,Ltd. val rg1: RunnableGraph[Cancellable] = src.to(sink) val rg2: RunnableGraph[Future[Int]] = src.toMat(sink)(Keep.right) val rg3: RunnableGraph[(Cancellable, Future[Int])] = src.toMat(sink)(Keep.both) val (cancellable, futureInt) = rg3.run() ※src.toMat(sink)(Keep.left)と同義
  26. 26. copyright Fringe81 Co.,Ltd. val src: Source[String, Cancellable] = Source(initialDelay = 0.second, interval = 100.millis, tick = "msg") val sink: Sink[String, Future[Int]] = Sink.fold[Int, String](0){ case (sum, _) => sum + 1 } val rg: RunnableGraph[(Cancellable, Future[Int])] = src.toMat(sink)(Keep.both) val (cancellable, futureInt) = rg.run() futureInt.foreach(println) Thread.sleep(1000 * 5) cancellable.cancel()
  27. 27. copyright Fringe81 Co.,Ltd. ・Publisher(Reactive Stream)から Source#apply
  28. 28. copyright Fringe81 Co.,Ltd. 実行時の挙動確認 通常のScala Collectionとの違い
  29. 29. copyright Fringe81 Co.,Ltd. (1 to 3) .map{ i => println(s"A: $i"); i } .map{ i => println(s"B: $i"); i } .foreach(i => println(s"C $i")) A: 1 A: 2 A: 3 B: 1 B: 2 B: 3 C: 1 C: 2 C: 3 Scala Collection
  30. 30. copyright Fringe81 Co.,Ltd. Source(1 to 3) .map{ i => println(s"A: $i"); i } .map{ i => println(s"B: $i"); i } .runForeach(i => println(s"C: $i")) A: 1 A: 2 B: 1 A: 3 B: 2 C: 1 B: 3 C: 2 C: 3 Akka Stream
  31. 31. copyright Fringe81 Co.,Ltd. source map:A map:B sink:C 1 1 2 3 2 3 1 2 3 1 2 3 各ステージの処理は 並行に実行される
  32. 32. copyright Fringe81 Co.,Ltd. source map:A map:B sink:C 1 1 2 3 2 3 1 2 3 1 2 3 ステージ内では 一件ずつ逐次処理
  33. 33. copyright Fringe81 Co.,Ltd. Backpressureの挙動確認 スレッドとバッファの関係
  34. 34. copyright Fringe81 Co.,Ltd. Backpressure? (背圧制御) 上流と下流のデータ流量制御の仕組み バッファ溢れを防ぐ
  35. 35. copyright Fringe81 Co.,Ltd. PushModel  上流が下流にデータを流し続ける  下流側で処理追いつかずバッファ溢れの可能性 Pull Model  下流から上流にリクエストするとデータが流れる  溢れないが下流側の待ちが大きくなる dynamic Push/Pull Model  下流から上流にn件リクエストする  上流は下流に要求分流す   initial-buffer-size(4), max-buffer-size(16)
  36. 36. copyright Fringe81 Co.,Ltd. implicit val system = ActorSystem() implicit val materializer = ActorMaterializer()
  37. 37. copyright Fringe81 Co.,Ltd. // スレッドプールの定義 implicit val system = ActorSystem() // バッファの定義 implicit val materializer = ActorMaterializer() akka.actor.default-dispatcher.fork-join-executor.parallelism-max = 1 akka.stream.materializer { initial-input-buffer-size = 1 max-input-buffer-size = 1 }
  38. 38. copyright Fringe81 Co.,Ltd. このうち mapCはかなり重い処理とする source mapA mapB sinkmapC heavy!
  39. 39. copyright Fringe81 Co.,Ltd. source mapA mapB mapC 1 1 2 3 4 5 6 7 ... 2 3 1 1 2 sink 1 2 2 スレッド = 1 バッファ = 1 3 3 4 3 ※ は 各ステージ上での 処理実行を表す
  40. 40. copyright Fringe81 Co.,Ltd. source mapA mapB mapC 1 1 2 3 4 5 6 7 ... 2 3 1 sink 1 2 2 スレッド = 1 バッファ = 2 3 2 4 1 2 4 5
  41. 41. copyright Fringe81 Co.,Ltd. source mapA mapB mapC 1 1 2 3 4 5 6 7 ... 2 3 1 sink 1 スレッド = 2 バッファ = 2 2 4 1 2 4 5 6 3 スレッドは2本あるので 1の処理中も上流は 処理が行われる
  42. 42. copyright Fringe81 Co.,Ltd. source mapA mapB mapC 1 1 2 3 4 5 6 7 ... 2 3 1 sink 1 スレッド = 2 バッファ = 2 2 4 1 2 4 5 6 3 スレッドは1本余っているが バッファ = 2に達しており バックプレッシャーが効いて 上流は処理が行われない
  43. 43. copyright Fringe81 Co.,Ltd. source mapA mapB mapC 1 1 2 3 4 5 6 7 ... 2 3 1 sink 1 スレッド = 2 バッファ = 2 2 4 1 2 4 5 6 3 mapCでは1の処理が終わって 2の処理が始まった。 これにより上流のバッファに1つ空きが 出来たので上流では処理が1つ進む
  44. 44. copyright Fringe81 Co.,Ltd. source mapA mapB mapC 1 1 2 3 4 5 6 7 ... 2 3 1 sink 1 スレッド = 2 バッファ = 2 2 4 1 2 4 5 6 3 スレッドは1本余っているが バッファ = 2に達しており バックプレッシャーが効いて 上流は処理が行われない mapCへの 大量流入を 防ぐ
  45. 45. copyright Fringe81 Co.,Ltd. バックプレッシャーが効いて 上流がストップしている状態を 回避/改善しようとすると? 案1:上流の処理を進める為の施策 案2:重いmapCを改善する施策
  46. 46. copyright Fringe81 Co.,Ltd. 案1-1: bufferステージを置く 上流の処理を進める施策
  47. 47. copyright Fringe81 Co.,Ltd. 重い処理の前にbufferステージを設けることで 上流の処理を進めることが出来る。 ストリーム全体では各ステージのバッファは 2としていても bufferステージのバッファは4といったように 異なる値を設定することが出来る。 ※なおbufferステージ以外でも個別にバッファ数を指定可能 val buffer = Flow[Int].buffer(4, OverflowStrategy.backpressure) ... mapB.via(buffer).via(mapC) ...
  48. 48. copyright Fringe81 Co.,Ltd. Flow[Int].buffer(4, OverflowStrategy.dropNew) ただし設定したバッファ値に 達した場合はBPが効く bufferの前後で極端な処理速度の差が ある場合はあまり効果ない 捨てる指示をすれば上流の処理は続行
  49. 49. copyright Fringe81 Co.,Ltd. 案1-2: conflateステージを置く 上流の処理を進める施策
  50. 50. copyright Fringe81 Co.,Ltd. def conflate[S](seed: Out => S)(aggregate: (S, Out) => S) ... .conflate(List(_)){ (elems, elem) => elem :: elems } ... ← 要素を捨てて良いなら ... .conflate(identity){ (e, _) => e } ... BPが効いている間、aggregate関数が実行される ※下流へはList[T] ※下流へはT まとめあげ効果で下流へのデータ数が減る 下流が要素数に応じて遅くなるなら効果はない
  51. 51. copyright Fringe81 Co.,Ltd. 案2-1: mapAsyncステージに変える 重いmapCを改善する施策
  52. 52. copyright Fringe81 Co.,Ltd. val mapC = Flow[Int].mapAsync(4) { n => Future { 重い処理 } } 処理の終了を待たずに 次の処理を開始する ※入力と出力の順序は保証される mapC 1 2 3 4
  53. 53. copyright Fringe81 Co.,Ltd. 案2-2: Fan-Outな部品を用い parallelに処理する 重いmapCを改善する施策
  54. 54. copyright Fringe81 Co.,Ltd. Balanceは入力1、出力NなFan-Outな部品 均等に下流に流す Mergeは入力N、出力1なFan-Inな部品 同期はしない 来たものから下流に流す ※順序は保証されなくなる balance merge 元のmapC 元のmapC
  55. 55. copyright Fringe81 Co.,Ltd. 新しいmapC 新しいFlowとしてmapCを定義出来る balance merge 元のmapC 元のmapC balance merge 元のmapC 元のmapC 新しいmapC
  56. 56. copyright Fringe81 Co.,Ltd. val mapC = Flow() { implicit builder => import FlowGraph.Implicits._ val balance = builder.add(Balance[Int](2)) val merge = builder.add(Merge[Int](2)) val map = Flow[Int].map(重い処理) balance ~> map ~> merge balance ~> map ~> merge (balance.in, merge.out) } Flowは入力と出力の ポートを1つずつ持つ 要素追加 データフロー定義
  57. 57. copyright Fringe81 Co.,Ltd. val runnableGraph = FlowGraph.closed() { implicit builder => import FlowGraph.Implicits._ val balance = builder.add(Balance[Int](2)) val merge = builder.add(Merge[Int](2)) val src = Source(1 to 10) val mapFlow = Flow[Int].map(_ * 2) val sink = Sink.foreach[Int](println) src ~> balance ~> map ~> merge ~> sink balance ~> map ~> merge } RunnableGraphを作ることも出来る
  58. 58. copyright Fringe81 Co.,Ltd. val runnableGraph = FlowGraph.closed() { implicit builder => import FlowGraph.Implicits._ val balance = builder.add(Balance[Int](2)) val merge = builder.add(Merge[Int](2)) val src = Source(1 to 10) val mapFlow = Flow[Int].map(_ * 2) val sink = Sink.foreach[Int](println) src ~> balance ~> map ~> merge ~> sink balance ~> map ~> merge } RunnableGraphを作ることも出来る 実際はコードフォーマッタに潰されるので こう書いています src ~> balance balance ~> map ~> merge balance ~> map ~> merge merge ~> sink
  59. 59. copyright Fringe81 Co.,Ltd. FlowGraphとMat値 val sink: Sink[Int, Future[Int]] = Sink.fold(0){_ + _} val rg: RunnableGraph[Future[List[Int]]] = FlowGraph.closed(sink, sink) ((f1,f2) => Future.sequence(f1 :: f2 :: Nil)) { implicit builder => (sink1, sink2) => import FlowGraph.Implicits._ val balance = builder.add(Balance[Int](2)) Source(1 to 10) ~> balance ~> sink1 balance ~> sink2 } val ret: Future[List[Int]] = rg.run()
  60. 60. copyright Fringe81 Co.,Ltd. その他の Fan-Out, Fan-Inな部品
  61. 61. copyright Fringe81 Co.,Ltd. <Fan-Out> Balance 入力を均等に出力に振り分ける Broadcast 入力を全出力に等しく流す Unzip (A,B)の入力をAの出力とBの出力に流す UnZipWith 任意の型の入力をタプルにして出力 FlexiRoute Fan-Out型の部品を作るためのベース
  62. 62. copyright Fringe81 Co.,Ltd. <Fan-In> Merge 複数入力を1本に 同期することなしに来たものから出力する Zip 2つの入力AとBを(A,B)にして出力する 同期する ZipWith 2つの入力AとBを(A,B)にして出力する 同期する (A,B)を任意の型に加工して出力する Concat 1つ目の入力を流し終えたら2つ目の入力を流す FlexiMerge Fan-In型の部品を作るためのベース
  63. 63. copyright Fringe81 Co.,Ltd. Error Handling
  64. 64. copyright Fringe81 Co.,Ltd. ・null要素は流せない ・例外が起きるとストリームは失敗として終了 Stop ストリーム失敗終了(default) Resume 該当の要素を捨てて次の処理を再開 Restart ・該当の要素を捨てる ・そのステージを再作成する ・処理を再開 ※fold等状態を持つものは状態がクリアされてしまうので注意 Supervision Strategies
  65. 65. copyright Fringe81 Co.,Ltd. Test libraryDependencies += Seq( …, "com.typesafe.akka" % "akka-testkit_2.11" % "2.3.14" % "test", "com.typesafe.akka" % "akka-stream-testkit-experimental_2.11" % "1.0" % "test" )
  66. 66. copyright Fringe81 Co.,Ltd. 本番用 Source 本番用 Sink 本番用 Flow 本番用 Flow テスト用 Source テスト用 Sink SourceやSinkは外部環境との接続点になりがちで テストしづらい事が多い。 テスト時はテスト用のデータを流すSourceとつなげた り、akka-stream-testkitに用意されているTestSinkと つなげて期待通りの結果が流れてくるかを確認したり する。
  67. 67. copyright Fringe81 Co.,Ltd. val probe = source.runWith(TestSink.probe[Result]) probe .request(2) .expectNext(Result(1),Result(2)) .request(100) .expectNext(Result(3)) .expectComplete() requestで下流から上流へデータを要求できる expectNextで流れてくるデータの確認 最後にデータが全て流れ終わったかどうかの確認
  68. 68. copyright Fringe81 Co.,Ltd. ありがとうございました

×