Top Banner
ScalaMatsuri 2016 なぜリアクティブは重要か 岡本 雄太 (@okapies) 2016/01/30 https://www.flickr.com/photos/livenature/204420128
81

なぜリアクティブは重要か #ScalaMatsuri

Apr 16, 2017

Download

Software

Yuta Okamoto
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: なぜリアクティブは重要か #ScalaMatsuri

ScalaMatsuri 2016

なぜリアクティブは重要か岡本 雄太 (@okapies)

2016/01/30

https://www.flickr.com/photos/livenature/204420128

Page 2: なぜリアクティブは重要か #ScalaMatsuri

自己紹介

• 岡本 雄太(@okapies)

• 製造業で働くソフト屋さん

• Scala と Scala OSSs 愛好家

• 最近の仕事はインフラエンジニアっぽい感じ

• ScalaMatsuri 2016 準備委員会 運営委員

Page 3: なぜリアクティブは重要か #ScalaMatsuri

公開してる OSS

• finagle-kafka (https://github.com/okapies/finagle-kafka)

• sircuit (https://github.com/okapies/sircuit)

• rx-process (https://github.com/okapies/rx-process)

Page 4: なぜリアクティブは重要か #ScalaMatsuri

書き物

• 翻訳:

• リアクティブ宣言 v2.0

• Effective Scala 日本語版

• 命令型のコールバック、関数型のプロミス

• ブログ記事 (http://okapies.hateblo.jp/):

• 非同期ストリーム処理の標準化を目指す "Reactive Streams" とは

• 関数型プログラマのための Rx 入門

• マイクロサービスが Scala を選ぶ3つの理由

Page 5: なぜリアクティブは重要か #ScalaMatsuri

関連するセッション

• 12:00 - 12:40(国際交流会議場):

• リアクティブ・マイクロサービス (Christopher

Hunt)

• 15:00 - 15:40(メディアホール):

• レジリエンスが無ければ、他は無いも同じ (Jonas

Bonér)

Page 6: なぜリアクティブは重要か #ScalaMatsuri

今日のソフト開発が直面する課題

• 非同期&イベント駆動プログラミング

• 並行・並列処理

• システムと組織のスケーラビリティ

• 耐障害性(マイクロサービス)

Page 7: なぜリアクティブは重要か #ScalaMatsuri
Page 8: なぜリアクティブは重要か #ScalaMatsuri

どこでもリアクティブ!

• フロントエンドからバックエンドまで、様々な文脈で〈リアクティブ〉がキーワードに

• 互いに似ているけど異なる様々なコンセプト:

• Reactive Programming

• Reactive Streams

• Reactive Manifesto

Page 9: なぜリアクティブは重要か #ScalaMatsuri

フロントエンド GUI

マルチクリックストリーム

https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

250 ミリ秒毎にクリックを集積 リストを長さ

にマッピング

RxJS による非同期クリックストリーム

Page 10: なぜリアクティブは重要か #ScalaMatsuri

GUI とネットワークサービスhttps://github.com/reark/reark

RxJava + Android製のデモアプリ

非同期 GUI イベントと JSON API 呼び出 しを並行処理として組み合わせる

Page 11: なぜリアクティブは重要か #ScalaMatsuri

マイクロサービス

val userAndTweets = Future.join( userService.findByUserId(userId), tweetService.findByUserId(userId))

find

finduserId userAndTweets

User Service

Tweet Service

http://www.slideshare.net/knoldus/finagle-by-twitter-engineer/16

join

他のマイクロサービスへクエリを投げ、全ての応答が揃ったら非同期に集約してタプルにする

Twitter Finagle

Page 12: なぜリアクティブは重要か #ScalaMatsuri

ビッグデータ処理https://speakerdeck.com/googlecloudjapan/google-cloud-dataflowwoli-jie-suru

ビッグデータの分散並列処理

Google Cloud Dataflow

Page 13: なぜリアクティブは重要か #ScalaMatsuri

Reactive Streams が JDK 9 に

Page 14: なぜリアクティブは重要か #ScalaMatsuri

Reactive?

Page 15: なぜリアクティブは重要か #ScalaMatsuri

リアクティブ ◯◯

プログラミングモデル? !

ランタイムエンジン? !

アーキテクチャ?=

文脈によってかなり意味付けが異なるのが実情

Page 16: なぜリアクティブは重要か #ScalaMatsuri

リアクティブの基盤

• リアクティブなコンポーネント

!

• リアクティブなデータフロー

in out

1

2

AB C

Page 17: なぜリアクティブは重要か #ScalaMatsuri

リアクティブなコンポーネント

• 入力にのみ反応 (react) してデータを出力する

• 自己完結性

in out

関数? オブジェクト? アクター? サブシステム?

Page 18: なぜリアクティブは重要か #ScalaMatsuri

リアクティブなデータフロー

Source

Source Sink

in out

コンポーネントの入力と出力を結びつけてデータを運搬するパイプライン

Page 19: なぜリアクティブは重要か #ScalaMatsuri

リアクティブ ◯◯

プログラミングモデル !

ランタイムエンジン !

アーキテクチャ=

vs

vs

Page 20: なぜリアクティブは重要か #ScalaMatsuri

課題(再掲)

• 非同期&イベント駆動プログラミング

• 並行・並列処理

• システムと組織のスケーラビリティ

• 耐障害性

Page 21: なぜリアクティブは重要か #ScalaMatsuri

コールバックじゃダメなの?

// asynchronous eventdef mouseClick(f: (Int, Int) => Unit): Unit!// register a callback as an argumentmouseClick { case (x, y) => println(s"x: $x, y: $y”) }

コールバック

Page 22: なぜリアクティブは重要か #ScalaMatsuri

コールバック地獄

• コードのモジュール化が困難

• 状態(副作用)やデータの依存関係の管理が困難

• 実行順序の制御が困難(外部イベント次第で変化する)

Page 23: なぜリアクティブは重要か #ScalaMatsuri

破滅のピラミッド

var g = ...!step1 { a => step2 { b => step3 { c => step4 { d => // do something with a, b, c, d and g } } }}

依存する非同期ステップがピラミッドのように積み上がる

外側のスコープの状態を暗黙に参照していてモジュール性が低い

Page 24: なぜリアクティブは重要か #ScalaMatsuri

リアクティブなコンポーネント• データフローから非同期イベントが入力されたときだけ反応する

in out

Page 25: なぜリアクティブは重要か #ScalaMatsuri

自己完結性• 各コンポーネントの内部状態は互いに隔離され、かつ独立したライフサイクルを持つ

• 自己完結性があると非同期処理がやりやすい

? ?in out

× ×外側の変数を暗黙に使わない

Page 26: なぜリアクティブは重要か #ScalaMatsuri

利点• モジュール性(組み合わせ可能性)が向上

• 状態や障害の封じ込めが容易になる

? ?in out

× ×

Page 27: なぜリアクティブは重要か #ScalaMatsuri

実行順序と依存性

• 非同期プログラミングで実行順序をどうやって制御すればいいか?

• 解決策: リアクティブ・プログラミング

Page 28: なぜリアクティブは重要か #ScalaMatsuri

http://en.wikipedia.org/wiki/Reactive_programming

〈データフロー〉と〈変更の伝播〉を指向するパラダイム

Page 29: なぜリアクティブは重要か #ScalaMatsuri

データフロー

g1

g2

h

Source

Source Sink

fin out

演算の間を流れるデータの有向グラフ

Page 30: なぜリアクティブは重要か #ScalaMatsuri

一般的な (命令型の) プログラム

A = 1;B = 2;C = (A+1) + (B-1)*2;

上から順に実行する

Page 31: なぜリアクティブは重要か #ScalaMatsuri

-1

×2

+

+1A

B C

命令型コードをデータフローにA = 1;B = 2;C = (A+1) + (B-1)*2;

1

2 41 2

2

Page 32: なぜリアクティブは重要か #ScalaMatsuri

実行モデル

• データフローそのものは、変数と演算の間の依存関係を記述しているだけ

• グラフの具体的な計算方法は実行モデルが決める

AB C

+1

—1

×2

+A = 1;B = 2;C = (A+1) + (B-1)*2;

Page 33: なぜリアクティブは重要か #ScalaMatsuri

-1

×2

+

+1A

B C

変数への再代入A = 1; B = 2;C = (A+1) + (B-1)*2; A = 2;

1 $ 2

2 4

A の変更はC に伝搬しない

命令型の実行モデル

××

××× ×

Page 34: なぜリアクティブは重要か #ScalaMatsuri

-1

×2

+

+1A

B C

変数への再代入A := 1; B := 2; C := (A+1) + (B-1)*2; A := 2;

1 $ 2

4 $ 52

1 $ 3

1 2A の変更が

C に伝搬する

リアクティブの実行モデル

Page 35: なぜリアクティブは重要か #ScalaMatsuri

-1

×2

+

+1A

B C

変数への再代入

2

5 $ 72 $ 31 $ 2 2 $ 4

3

C := (A+1) + (B-1)*2; A := 2;B := 3;

リアクティブの実行モデル

B の変更がC に伝搬する

Page 36: なぜリアクティブは重要か #ScalaMatsuri

-1

×2

+

+1A

B C

変数への再代入

2 $ 0

7 $ 532 4

3 $ 1

A := 2; B := 3; A := 0;

リアクティブの実行モデル

A の変更がC に伝搬する

Page 37: なぜリアクティブは重要か #ScalaMatsuri

リアクティブプログラミング !

!

関数型 リアクティブプログラミング

(FRP)≒

一般に〈リアクティブプログラミング〉というと 〈関数型~〉(FRP) を指すことが多い

Page 38: なぜリアクティブは重要か #ScalaMatsuri

例 (Akka Streams):

implicit val system = ActorSystem()implicit val mat = ActorMaterializer()!val a = Source(...)val b = Source(...)!val a1 = a.map(_ + 1)val b1 = b.map(_ - 1).map(_ * 2)!val c = (a1 zip b1).map{case (a, b) => a + b}!c.runWith(Sink.foreach(println))(mat)

AB C

+1

—1

×2

+

先ほどのデータフローを関数型 DSL で記述する

Page 39: なぜリアクティブは重要か #ScalaMatsuri

例 (Akka Streams):

implicit val system = ActorSystem()implicit val mat = ActorMaterializer()!val a = Source(...)val b = Source(...)!val a1 = a.map(_ + 1)val b1 = b.map(_ - 1).map(_ * 2)!val c = (a1 zip b1).map{case (a, b) => a + b}!c.runWith(Sink.foreach(println))(mat)入力に適用する関数を

高階関数 map で繋ぎ合わせる

関数入力

AB C

+1

—1

×2

+

Page 40: なぜリアクティブは重要か #ScalaMatsuri

関数型とリアクティブの関係

• なぜリアクティブ・プログラミングには関数型プログラミングが適しているのか?

• この疑問に答えるには「なぜ関数プログラミングは重要か」を知る必要がある

Page 41: なぜリアクティブは重要か #ScalaMatsuri

なぜ関数プログラミングは重要か

• QuickCheck の開発や QuviQ の創業者として知られるジョン・ヒューズ博士の著名な論文

• 初版は 1984 年(30 年前!)

• 関数型プログラミングを活用して、コードのモジュール性を高める方法について論じている

http://www.cse.chalmers.se/~rjmh/Papers/whyfp.html

Page 42: なぜリアクティブは重要か #ScalaMatsuri

関数型の〈糊〉• 関数型における二つの重要な〈糊〉

• 遅延評価

• 高階関数(コンビネータ)

「元の問題を分割する方法は、解と解を貼り合わせる方法に直接に依存する。」

Page 43: なぜリアクティブは重要か #ScalaMatsuri

遅延評価

class Cons[A](hd: A, tl: => List[A]) extends List[A]!def nats(n: Int): List[Int] = new Cons(n, nats(n+1))def fizzbuzz(n: Int) = n match { case _ if n % 15 == 0 => "FizzBuzz" case _ if n % 3 == 0 => "Fizz" case _ if n % 5 == 0 => "Buzz" case _ => n.toString}nats.map(fizzbuzz).take(100).foreach(println)

必要呼び (プル型)

コードを生成器と選択器の 組み合わせでモジュール化できる

無限リスト

Page 44: なぜリアクティブは重要か #ScalaMatsuri

高階関数

• プログラムを、汎用的な高階関数とユースケースに特化した関数に分けてモジュール化

!

!

• ビジネスロジックと、それが乗っかるデータ型の文脈を分離できる

set. map(_ + 1) // Set[A]map. map(_ + 1) // Map[A, B]list.map(_ + 1) // List[A]

局所化された文脈 ビジネスロジックを使い回せる

Page 45: なぜリアクティブは重要か #ScalaMatsuri

FP の糊を RP に適用すると?

• 遅延評価:

• 非同期イベントを少しずつ処理する生成器・選択器のパイプラインとしてプログラムを構成する(プッシュ型)

• 高階関数:

• ビジネスロジックと、それが乗っかる非同期イベント駆動の文脈を分離する

Page 46: なぜリアクティブは重要か #ScalaMatsuri

FRP の〈糊〉

implicit val system = ActorSystem()implicit val mat = ActorMaterializer()!val a = Source(...)val b = Source(...)!val a1 = a.map(_ + 1)val b1 = b.map(_ - 1).map(_ * 2)!val c = (a1 zip b1).map{case (a, b) => a + b}!c.runWith(Sink.foreach(println))

AB C

+1

—1

×2

+

生成器

非同期の文脈を局所化した高階関数 (map, zip 等)を使い、 ビジネスロジックをパイプライン化する

選択器

局所化された非同期の文脈

Page 47: なぜリアクティブは重要か #ScalaMatsuri

• 多くの FRP のデータフロー記述は宣言型 DSL: 構築したデータフローを実際にスケジュールし実行するのはランタイムの役割

what と how の分離

implicit val system = ActorSystem()implicit val mat = ActorMaterializer()!val c = (a1 zip b1).map{case (a, b) => a + b}!c.runWith(Sink.foreach(println))(mat) ランタイム

Page 48: なぜリアクティブは重要か #ScalaMatsuri

what と how の分離

Input

Input

Output(2) ランタイム

(1) プログラミングモデル (DSL)

(how を実行する = 変更の伝搬)

(what を記述する = データフロー)

Page 49: なぜリアクティブは重要か #ScalaMatsuri

リアクティブ ◯◯

プログラミングモデル !

ランタイムエンジン !

アーキテクチャ=

vs

vs

リアクティブなプログラミングモデルとランタイムには 密接な関係がある

Page 50: なぜリアクティブは重要か #ScalaMatsuri

可搬性(マルチプラットフォーム)

• リアクティブなプログラムは、ランタイムによって様々なアーキテクチャにマッピングできる

• 単一マシン

• GPU クラスタ

• 分散環境

Page 51: なぜリアクティブは重要か #ScalaMatsuri

最適化

• データフローの性能や安定性をランタイムが最適化できる

• 融合、データ局所化、キャッシュ

• 並列分散化

• 検証

Page 52: なぜリアクティブは重要か #ScalaMatsuri

例: 融合 (Fusing)

• Akka Streams 2.0 の新機能

This new abstraction … is called fusing. This feature … will be now possible to execute multiple stream processing steps inside one actor, reducing the number of thread-hops where they are not necessary … will increase performance for various use cases, including HTTP.

http://akka.io/news/2015/11/05/akka-streams-2.0-M1-released.html

複数の処理ステップを一つにまとめて性能向上

Page 53: なぜリアクティブは重要か #ScalaMatsuri

実装例

• データフロー DSL とランタイムの組み合わせは、近年、様々な分野で適用されている

• Akka Streams, ReactiveX, …

• 科学技術計算: TensorFlow, Halide

• ビッグデータ処理: Spark, Google Cloud Dataflow,

Asakusa Framework, Gearpump

Page 54: なぜリアクティブは重要か #ScalaMatsuri

例: TensorFlow

http://download.tensorflow.org/paper/whitepaper2015.pdf

Page 55: なぜリアクティブは重要か #ScalaMatsuri

課題(再掲)

• 非同期&イベント駆動プログラミング

• 並行・並列処理

• システムと組織のスケーラビリティ

• 耐障害性

DONE!

Page 56: なぜリアクティブは重要か #ScalaMatsuri

リアクティブ ◯◯

プログラミングモデル !

ランタイムエンジン !

アーキテクチャ=

vs

vs

Page 57: なぜリアクティブは重要か #ScalaMatsuri

単一マシン !

!

分散システム

Page 58: なぜリアクティブは重要か #ScalaMatsuri

なぜ分散システムか?

• 非同期&イベント駆動プログラミング

• 並行・並列処理

• システムと組織のスケーラビリティ

• 耐障害性

→ リアクティブ・システム

(マイクロサービス)

Page 59: なぜリアクティブは重要か #ScalaMatsuri

http://www.reactivemanifesto.org/ja

Page 60: なぜリアクティブは重要か #ScalaMatsuri

アプリケーションの要求の変化

数年前 現在

Configuration 数十のサーバ 数千のマルチコアプロセッサ

Responsetime 秒単位 ミリ秒単位

Availability数時間の

オフラインメンテナンス稼働率 100%

Data size ギガバイト単位 ペタバイト単位

Page 61: なぜリアクティブは重要か #ScalaMatsuri

システムの構築方法の変化

“大規模システムを構築する組織はこの変化に対処する設計原則を

すでに発見している”

“そのような特徴を備えるシステムをReactive Systems と呼ぼう”

http://www.reactivemanifesto.org/ja

Page 62: なぜリアクティブは重要か #ScalaMatsuri

リアクティブシステムの性質

リアクティブシステムの四つの特徴: 即応性、弾力性、レジリエンス、メッセージ駆動

http://www.slideshare.net/Typesafe_Inc/going-reactive-2016-data-preview/6

Page 63: なぜリアクティブは重要か #ScalaMatsuri

リアクティブシステムの性質実現したい価値:

ユーザへ迅速かつ一貫した速度でサービスを提供する

障害時にも即応性を維持する

非同期メッセージパッシングが全ての基盤である

負荷が変動しても即応性を維持する

http://www.slideshare.net/Typesafe_Inc/going-reactive-2016-data-preview/6

Page 64: なぜリアクティブは重要か #ScalaMatsuri

RS におけるコンポーネント

• メッセージのみを介して互いに通信する

• 自己完結しており非同期(バイナリ)境界で互いに隔離されている

アクター サブシステム

in out

Page 65: なぜリアクティブは重要か #ScalaMatsuri

メッセージ駆動が達成するもの

• 弾力性: スケーラビリティ、シャーディング、レプリケーション、位置透過性

• レジリエンス: レプリケーション、隔離、タスクやエラーの委譲 (“Let it crash”)

Page 66: なぜリアクティブは重要か #ScalaMatsuri

リアクティブシステムをどう構築するか?

マニフェストの中で、その実現方法について規範的なことは述べたくなかった。 — Martin Thompson

• マニフェストは、リアクティブなコンポーネントやシステムの性質や品質についてのみ記述しており、具体的な実現方法には触れていない

• 実例としてマイクロサービス・アーキテクチャ (MSA) を見てみよう

http://www.infoq.com/news/2014/10/thompson-reactive-manifesto-2

Page 67: なぜリアクティブは重要か #ScalaMatsuri

マイクロサービス・アーキテクチャ

• Amazon, Netflix, Twitter のような巨大な開発組織をスケールさせるための方法論

• サービスを、ビジネス遂行能力に沿って小さく独立したモジュールに分ける(c.f. コンウェイの法則)

• リアクティブシステムの実例の一つとみなせる

Page 68: なぜリアクティブは重要か #ScalaMatsuri

STORAGE & RETRIEVAL

LOGICPRESENTATIONROUTING

Redis

Memcache

Flock

T-Bird

MySQLTweet

User

Timeline

Social Graph

DMs

API

Web

Monorail

TFE

HTTP Thrift “Stuff”http://monkey.org/~marius/scala2015.pdf

例: Twitter における マイクロサービス

Page 69: なぜリアクティブは重要か #ScalaMatsuri

システムレベルのデータフロー

• MSA は(リアクティブな)コンポーネントと、そのビジネス上の依存関係で構成される • つまりシステムレベルのデータフロー

• ならば、分散システム全体をコードとして記述できないだろうか?

AB C

Page 70: なぜリアクティブは重要か #ScalaMatsuri

リアクティブ・ビッグデータ

• 近年のビッグデータ処理フレームワークでは、リアクティブなアーキテクチャが採用されることが多い

• Spark

• Google Cloud Dataflow

• Gearpump (Intel)

• Asakusa Framework

Page 71: なぜリアクティブは重要か #ScalaMatsuri

https://speakerdeck.com/googlecloudjapan/google-cloud-dataflowwoli-jie-suru

DAG でデータ処理パイプラインを記述

in Google Cloud Dataflow

Page 72: なぜリアクティブは重要か #ScalaMatsuri

DAG on Spark

https://cloud.githubusercontent.com/assets/2133137/7625997/e0878f8c-f9b4-11e4-8df3-7dd611b13c87.png

実行中の Spark ジョブを DAG として可視化した例

Page 73: なぜリアクティブは重要か #ScalaMatsuri

http://www.gearpump.io/overview.html

Gearpump の Akka を使ったリアクティブ・アーキテクチャ

Page 74: なぜリアクティブは重要か #ScalaMatsuri

http://knowledge.sakura.ad.jp/tech/4016/http://docs.asakusafw.com/preview/ja/html/asakusa-on-spark/user-guide.html

Asakusa Framework

一つの DSL アプリを Hadoop でも Spark でもポータブルに実行できる

Page 75: なぜリアクティブは重要か #ScalaMatsuri

Apache Dataflow (New!)

http://googlecloudplatform.blogspot.co.uk/2016/01/Dataflow-and-open-source-proposal-to-join-the-Apache-Incubator.html

Google 主導によるデータフロー記述の標準化の取り組み

Page 76: なぜリアクティブは重要か #ScalaMatsuri

https://speakerdeck.com/googlecloudjapan/google-cloud-dataflowwoli-jie-suru

ランタイムとしてのGoogle Cloud

Optimize

Schedule

Flow of pipelineUser code & SDK Monitoring UI

データフロー定義

データフロー・ランタイムとしての Google クラウドが データフローの最適化とタスクのスケジュールを行う

Page 77: なぜリアクティブは重要か #ScalaMatsuri

一般化すると…

ビッグデータにおけるリアクティブ・システムの アーキテクチャを一般化してみる

Dataflow

Reactive System

Cloud-level Runtime

Page 78: なぜリアクティブは重要か #ScalaMatsuri

一般化すると…

• クラウドレベルのランタイムは:

• 指定されたデータフローを最適化すると共に、リアクティブなコンポーネントをスケジューリングする

• YARN や      のような分散リソースマネージャからリソースを獲得する

• 確保したリソースにコンポーネントを配備し、リアクティブ・システムとして実行する

Dataflow

Reactive System

Cloud-level Runtime

Page 79: なぜリアクティブは重要か #ScalaMatsuri

ウェブサービスの配備自動化

• 現代の DevOps ツールは、主にノードごとにシステムを設定することに焦点を当てており、Dockerfile のような命令的な記述を用いている

• イミュータブル・インフラストラクチャは、本来、リアクティブなコンポーネントと宣言的なデータフローの組み合わせとして実現されるべきだったのでは?

Page 80: なぜリアクティブは重要か #ScalaMatsuri

まとめ

• リアクティブ・プログラミングとアーキテクチャによって、今日のソフト開発が直面する課題を解決できる:

• 非同期&イベント駆動プログラミング

• 並行・並列処理

• システムと組織のスケーラビリティ

• 耐障害性

Page 81: なぜリアクティブは重要か #ScalaMatsuri

まとめ

• リアクティブなコンポーネントとデータフローは、システムのあらゆる階層において非同期と分散の課題に対処する際に有効なツール

• プログラミングモデルよりもランタイムが提供する能力(性能、耐障害性、運用性)が重要な時代が到来しつつある