reactive systems と back pressure

44
Reactive Systems と Back Pressure 最先端情報吸収研究所(AIAL) 勉強会 2016年8月19日

Upload: akihiro-ikezoe

Post on 16-Jan-2017

680 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Reactive Systems と Back Pressure

Reactive Systems と Back Pressure最先端情報吸収研究所(AIAL) 勉強会

2016年8月19日

Page 2: Reactive Systems と Back Pressure

自己紹介

• 池添明宏 (いけぞえ あきひろ)

• Twitter: @zoetro

• 昔はロボットとか、C#とか、AngularJSとか。

• 最近はJavaとかScalaを書くことが多い。

Page 3: Reactive Systems と Back Pressure

本日の内容

• Reactive Systems

• 対障害性

• RxJavaのBack Pressure実装

• Back Pressureの活用

Page 4: Reactive Systems と Back Pressure

REACTIVE SYSTEMS

Page 5: Reactive Systems と Back Pressure

なぜReactiveが必要なのか

• さまざまな非同期イベントを扱う機会が増えている。

− GUI

− マイクロサービス

− ビッグデータ解析

− ノンブロッキングI/O

• 複雑になりがちな非同期処理をきれいに書きたい。

→ Reactive Programming

• 性能がよく、柔軟性・耐障害性の高いシステムをつくりたい。

→ Reactive Systems

Page 6: Reactive Systems と Back Pressure

Promise/Futureではダメなのか?

• ReactiveもPromise/Futureも非同期処理を扱うための手段。

• Promise/Futureが主に1回きりのイベントを取り扱うのに対して、

Reactiveではイベントストリームを扱う。

• Promise/Futureの強み

− 言語によっては async/await が利用できる。

− 標準で利用できるケースが多い。

• Reactiveの強み

− 様々なオペレータが用意されていて、複数のストリームを組み合わせたり、時間を

考慮した処理が簡単に書けたりする。

Page 7: Reactive Systems と Back Pressure

Webサーバのアーキテクチャ

• マルチプロセス/マルチスレッドモデル (Servletなど)

− 1つのリクエストを1つのプロセス/スレッドで捌く。

− リクエスト数が増えた場合にメモリ使用量が大幅に増える (C10K問題)

• イベント駆動モデル (Node.jsなど)

− 複数のリクエストを1つのスレッドで捌く。

− I/O処理でのブロックは禁止。すべてノンブロッキングI/Oを利用する。

• ハイブリッドモデル (Vert.x, Play Framework, Akka HTTPなど)

− イベント駆動モデルのノードを複数個用意し、メッセージをやり取りしながら連携する。

− マルチスレッドモデルとイベント駆動モデルの両方の利点を持つ。

同期処理でOK

Promise/FutureでOK

Reactiveが欲しい

Page 8: Reactive Systems と Back Pressure

Reactiveを取り入れたフレームワーク

• Webアプリケーションフレームワーク

− Spring Framework 5, Vert.x 3

• データベース

− Slick 3, MongoDB

• ライブラリ

− Akka Streams, RxJava, Reactor

• JVM系以外でも多数のライブラリ・フレームワークでReactiveな概念が

取り入れられている。

Page 9: Reactive Systems と Back Pressure

Reactive Systemの歴史

• Reactive Programmingとは

• Rx (Reactive Extensions)

• ReactiveX

• The Reactive Manifesto

• Reactive Streams

Page 10: Reactive Systems と Back Pressure

• 時間や外部の入力と共に変化する値を、反応的 (reactive) に処理するプロ

グラミングパラダイム。

• アニメーション、GUIプログラミング、センサやロボット制御プログラム

などを実現するときに役立つ。

• 2種類の入力の概念を扱う

− Behavior: 時間に伴い連続的に変化する値 (温度、株価など)

− Signal: 時間順に並ぶ離散的なイベント (マウスクリック、人物検知センサなど)

• Haskell界隈ではFRP (Functional Reactive Programming) として、古くか

ら利用されている。

Reactive Programmingとは

Page 11: Reactive Systems と Back Pressure

Reactive Programmingとは

• コード例

• イベントストリーム

var a = 1var b = a + 1a = 10 // aを書き換えるprint b // => 11

時間[t]

xs:[e1, e2, e3,e4, e5]

非同期に発生するイベントを無限リストのように扱う

Page 12: Reactive Systems と Back Pressure

Rx (Reactive Extensions)

• Microsoft Research社でErik Meijer氏が中心となり開発。

• 2009年にC#向けのライブラリとして公開された。2014年にはOSS化。

• 非同期に流れてくるデータに対して関数を適用するスタイルのライブラ

リ。

• FRPとLINQのコンセプトをベースに、シンプルかつ柔軟で実用性の高い

ライブラリとなっている。

Page 13: Reactive Systems と Back Pressure

Rx (Reactive Extensions)

• Rxの特徴

− Signalのみに特化

− エラーハンドリング

− リソース管理

− スケジューラ

− テストのための機能

− Hot Observable, Cold Observable

− LINQライクなAPI

− 豊富な関数群

Page 14: Reactive Systems と Back Pressure

Rx (Reactive Extensions)

• イベントを時間的に流れてくるデータの無限リストとして扱う。

• イベントに対しても、普通のリストと同じようにmap, reduce, filterな

どの処理が使える。

observable.filter(x -> x > 5).map(x -> x * x).subscribe(x -> out.println(x));

list.stream().filter(x -> x > 5).map(x -> x * x).forEach(x -> out.println(x));

Stream API RxJava

Page 15: Reactive Systems と Back Pressure

Rx (Reactive Extensions)

• コードはそっくりだが、データの

流れが違う。

• Iterator

− Action側からデータソースに対して

データを取りにいく (Pullスタイル)

• Observable

− データソース側からActionに対して

データを通知する (Pushスタイル)

Iterator<T>

Observable<T>

Action Action

T next() onNext(T)

Pullスタイル Pushスタイル

Page 16: Reactive Systems と Back Pressure

ReactiveX

• Rxを気に入った開発者たちが、次々と他の言語へ移植していった。

• Netflix社などが中心となり、各種言語でのRx実装をとりまとめている。

− RxJava, RxJS, RxSwift が人気。

− RxCpp, RxScala, Rx.rb, RxPy, RxKotlin, RxPHP などの実装もある。

− UniRx, RxAndroid, RxCocoa など、特定のフレームワーク向け実装もある。

• ドキュメントが充実している。

Page 17: Reactive Systems と Back Pressure

Reactive Streams

• JVMにおける非同期ストリーム処理のAPIの標準化

• Akka Streams, Reactor, RxJava, Ratpack, Vert.xなどが対応。

• Reactive Programmingをおこなう際には、上流から下流までインタ

フェースが統一されていることが望ましい。

• Java 9でReactive Streamsの標準インタフェースとしてFlow APIの導入

が検討されている。

Page 18: Reactive Systems と Back Pressure

The Reactive Manifesto

http://www.reactivemanifesto.org/

• Scalaを開発しているTypesafe社 (現Lightbend社) が提唱

• Reactiveをプログラミングモデルだけでなく、システムのアーキテクチャ

に対して適用。

• 下記の特徴を持ったアーキテクチャをReactive Systemsと呼ぶ。

− 即応性: システムは可能なかぎり素早く応答を返すこと。

− 耐障害性: システムは障害が発生しても即応性を保ち続けること。

− 弾力性: システムは処理量が変動しても即応性を保ち続けること。

− メッセージ駆動: 上記を達成するため、コンポーネント間の通信に非同期なメッセー

ジパッシングを利用する。

Page 19: Reactive Systems と Back Pressure

Reactive Systemsとは

ComponentComponent

Component• コンポーネントは分散配置可能。各コンポーネント

間では非同期なメッセージのやりとりをおこなう。

• コンポーネント内ではReactive Programmingのモ

デルを利用する。

Page 20: Reactive Systems と Back Pressure

対障害性

Page 21: Reactive Systems と Back Pressure

Reactive Systemsで起きがちな問題

• Reactive Systemsでは非同期のメッセージパッシングで

コンポーネント間の通信をおこなう。

• 下流のコンポーネントよりも上流のコンポーネントの処

理速度が早い場合、下流側のバッファがあふれてしまう。

Producer Consumer

処理が早い 処理が遅い

バッファのあふれ

Page 22: Reactive Systems と Back Pressure

対障害性を高めるために

• 大きなバッファを用意する。

• 下流のバッファがあふれないように流量を調整する。

• バッファがあふれたらデータをドロップする。時間をおいて再送する。

• コンポーネントの障害を他のコンポーネントに伝わらないようにする。

• リソースを増やして負荷分散をおこなう。

Page 23: Reactive Systems と Back Pressure

Reactive Manifesto & Reactive Streams

• Reactive Manifestoでは、下記の手段によってシステムの耐障害性を実

現すると記述している

− レプリケーション

− 障害の起きたコンポーネントの隔離

− Back Pressureによるフロー制御

• Reactive Streamsでは、Back Pressureを実現するためのインタフェー

スが規定されている。

Page 24: Reactive Systems と Back Pressure

分散メッセージングサービス

• 大きなバッファを用意して、メッセージをあふれにくく

する。

• Apache Kafka, Amazon Kinesis Streams

• 一時的な負荷上昇や、一時的なコンポーネントの障害に対応可能。

Producer Consumer

Consumerの速度に応じてメッセージを流す

下流は気にせずメッセージを流す

Page 25: Reactive Systems と Back Pressure

障害の伝搬

• いずれかのコンポーネントに障害が発生した時、それが他のコンポーネ

ントに伝搬してしまう可能性がある。

Component

Component

バッファのあふれ

ムリ…

thread

thread

thread

まだ?

まだ?

まだ?

リクエスト

リクエスト

リクエスト

Page 26: Reactive Systems と Back Pressure

障害の伝搬

• リクエストごとにスレッドを立てる場合、スレッドプールが枯渇して呼

び出し元のコンポーネントまでクラッシュしてしまう。

Component

Component

バッファのあふれ

ムリ…

thread

thread

thread

ムリ…

ムリ…

ムリ…

リクエスト

リクエスト

リクエスト

Page 27: Reactive Systems と Back Pressure

障害の隔離 (Circuit Breaker)

• 処理の失敗が連続した場合、Circuit Openな状態へと遷移。

• Openな場合は、即座にエラーを返したりキャッシュを返したりする。

• 時間をおいて復旧した場合は、Closed状態に遷移。

Component

Component

バッファのあふれ

ムリ…thread

thread

thread

リクエスト

リクエスト

リクエスト

ムリっぽいのでしばらく切断します

Page 28: Reactive Systems と Back Pressure

Back Pressure

• 下流から上流のコンポーネントに対して、受け入れ可能な

個数を通知する。

• 上流のコンポーネントでは、下流の速度にあわせてゆっく

りメッセージを送信したり、間に合わない分は捨てたりな

どの対策をおこなう。

Producer Consumer

バッファあと1個なら

大丈夫了解!

request(1)

Page 29: Reactive Systems と Back Pressure

Back Pressureでどこまで遡るの?

Component

Component Component

Component

• 最上流まで遡る

− 例えばユーザインタフェース

• 対処できるところまで遡る

− データサイズが小さい所

− DBやファイルの読み込みなど、待ちのつくれる所

ちょっと待って

ちょっと待って

待とう…

待とう…ちょっと待って

Page 30: Reactive Systems と Back Pressure

Back Pressureでどこまで遡るの?

• 各コンポーネントが速度を調整してバランスをとる

− 上流のスループットは落ちるが、システム全体として安定して動くようになる。

Component Component

ゆっくりお願いします

Component

本当はもっと速く処理できるけど、

ゆっくり送信

本当はもっと速く処理できるけど、

ゆっくり送信

Page 31: Reactive Systems と Back Pressure

RxJavaのBACK PRESSURE実装

Page 32: Reactive Systems と Back Pressure

RxJavaのBack Pressure実装

• 基本動作

• onBackpressureオペレータ

• merge

• publish

Page 33: Reactive Systems と Back Pressure

RxJavaのBack Pressure

• SubscriberがObservableをsubscribeする。

• このときSubscriberにProducerをセットする。

• SubscriberはProducerに受け取り可能なデータの数を伝える。

• ObservableはProducerを介して送信可否を判断する。

• 送信可能であれば、onNextを呼び出してデータを送信する。

Subscriber

Observable

Producer

onNext(x)

request(n)

Page 34: Reactive Systems と Back Pressure

RxJavaのBack Pressure: onBackpressure

• request()の呼び出しに応じて振る舞いを変更するためのオペレータが用

意されている。

• onBackpressureBuffer()

− データをバッファリング。キャパシティの設定、あふれた時に実行されるコール

バック処理、あふれた後にどうするかを指定できる。

• onBackpressureDrop()

− requestが0の間に受け取ったデータはすべて捨てる。

• onBackpressureLatest()

− requestが0の間に受け取ったデータは、最新のデータ以外すべて捨てる。

Page 35: Reactive Systems と Back Pressure

RxJavaのBack Pressure: onBackpressure

SubscriberObservable

onNext(x)

request(n)

onBackpressureDrop

onNext(x)

好きなタイミングでデータを送信する

requestが0でなければデータを送信する

受け入れ可能な数を通知する

requestが0の時に受け取ったデータは捨てる

Page 36: Reactive Systems と Back Pressure

RxJavaのBack Pressure: merge

• 複数のObservableをmergeした場合でも、Subscriberがrequestした数だけデータが

送信される。

• 例えばSubscriberがrequest(1)を送信した場合、Observable1かObservable2のどちら

かが1つデータを送信することができる。早い者勝ち。

Subscriber

Observable1onNext(x)

request(n)

merge

onNext(x)

Observable2

request(n)

onNext(x)

request(n)

Page 37: Reactive Systems と Back Pressure

RxJavaのBack Pressure: publish

• 複数のSubscriberにpublishする場合、Subscriberがrequestした数の最小値が上流へ

と要求される。

• 例えばSubscriber1がrequest(1), Subscriber2がrequest(2)を送った場合、Observable

はデータを1つだけ送信し、そのデータはpublishによって全Subscriberに分配される。

Subscriber1

Observable

onNext(x)

request(n)publish

onNext(x)

Subscriber2

request(n)

onNext(x)

request(n)

Page 38: Reactive Systems と Back Pressure

BACK PRESSUREの活用

Page 39: Reactive Systems と Back Pressure

背景

• ログ管理システムを開発

− 顧客環境から取得したログファイルを、社内のログ管理システムにアップロード

− ログデータはパースしてElasticsearchに登録

− Kibanaでログの分析をおこなう

• 利用ユーザ数が増えて一度に大量の登録処理が実行されると、一部のロ

グデータが失われる事態が発生した。

Page 40: Reactive Systems と Back Pressure

ログ管理システム

Elasticsearch

登録画面

Kibana

Log Files

upload

parse

bulkinsert

グラフの生成

一度に大量のログを登録すると、Elasticsearchのキューがあふれてしまう

Page 41: Reactive Systems と Back Pressure

Elasticsearch

• Bulk API: インデックスの作成・削除・更新などの処理を一括で処理する

仕組み。リクエストはキューに蓄えられ、順次処理される。

• キューがあふれたときに受け取ったデータはドロップされる。

• キューのサイズを変更することで、ドロップされにくくすることは可能。

− threadpool.bulk.queue_size: デフォルト50。-1で無制限。

− ただしサイズを大きく設定すると、サーバのスペックによってはメモリ不足になる

ので注意が必要。

Page 42: Reactive Systems と Back Pressure

Back Pressureを利用した改善策

• ElasticsearchのNodes Stats APIのでキューの状態を監視し、上流に受

け入れ可能な数を通知する。

• 上流では、受け入れ可能な数に応じて登録処理を実行。

• 登録タスクはサイズが小さいため、バッファがあふれる心配はない。

Elasticsearch

request(n)

受け入れ可能な数を通知

SubscriberObservable

キューをチェック

bulkinsertonNext(x)

受け入れ可能ならば次のタスクを処理

登録タスクのバッファ

Page 43: Reactive Systems と Back Pressure

Back Pressureを利用した改善策

• Back Pressureを利用することで、キューがあふれることなく、データ

を登録することができるようになった。

• Back Pressureを利用しなくても、キューをチェックしながら登録すれ

ばいいだけなのでは?

− Reactive Streamsの仕様に従っていると、上流側・下流側の実装を柔軟に他のもの

に変更しやすい。

− データの加工やバッファリングなど中間に様々な処理をはさんだり、コンポーネン

トを分散させたりもしやすい。

Page 44: Reactive Systems と Back Pressure

まとめ

• 非同期処理の記述性を向上させるReactive Programmingや、システム

の安定性を向上させるためのReactive Systemsが注目を集めている。

• Reactive Systemsの対障害性を向上させる方法の1つとして、Back

Pressureがある。

• RxJavaにおけるBack Pressureの実装を紹介した。

• ログ管理システムにおけるBack Pressureの活用例を紹介した。