せてぃーずノート

Javaのイベント参加レポートとかを書いたりします。

Spring Fest 2019メモその2 Reactive Spring

Josh LongさんがライブコーディングをしつつReactiveについて3時間弱熱く語ってくれるセッション。
すごく勉強になった。

リアクティブプログラミングは、より多くのユーザーリクエストを処理するための水平スケール依も効率がいい解決手段。
CPUに効率よく仕事をさせることができる。

これまでのプログラミングではCPUがIO待ちによるアイドリング状態が多い。
IO待ちの間、CPUは何も仕事をしていない。

リクエストを受け付けるため、大量のスレッドが待機状態にする必要がある(IO待ち)。
大量のリクエストを受付けるためにスレッドを増やすと、スレッド管理のためにOS、CPUに無駄な仕事が発生する。

それに対してリアクティブプログラミングはスレッドを効率よく使う。
データが発生するとコールバックで処理を行うため、スレッドをキープし続ける必要はない。

Javaの非同期のIOはJava 1.4でNIOによって実現可能。
18年前に出ているが、APIが使いにくいため使われていなかった。
また、無理に使わなくてもロードバランサーでどうにかできた。(非同期IOに比べれば効率は悪いが・・・)

リアクティブは4つのシンプルなインターフェースの構成。
Subscriber、Publisher、Processor、Subscription

Reactiveに対応したデータソースは、CosmosDB、GoogleのFirebase、Elasticsearchとか様々ある。
RDBSQL使いたい人のためにR2DBCを提供。
R2DBCはGAだが、SpringBootとのインテグレーションはまだ。

ポーリングはユーザーエクスペリエンスがよくない。
特に市場の株価のようなライブの情報が必要となる場合。
リアルタイムの通信が必要な場合、1ソケット1スレッドは効率悪い。
ユーザーが明示的にシャットダウンをしないとスレッドのロスも発生する。

Reactiveの背後にはスケジューラー(のようなもの)がいる
必要なスレッドはCPUのコアだけ。(デフォルト設定)
処理を書く際はブロッキングをしてはいけない
例えば4つのコアがあるときにブロッキングが発生すると、処理性能が25%停止する
ブロッキングしなければいけない場合、ソースで明示的にしなければいけない。

ブロッキングされている処理の検出はBlockHoundで可能

github.com

Reactiveの利点はユーザーの数を2倍にしつつデータセンターのコストをそのままにすること。
新しいプログラミングモデルを提供してくれる。
従来であればリクエストに対して成功・失敗のどちらかを返していたが、リアクティブではいろいろな応答を何回も返せる。

リクエスト数の上限を設定する場合、ノード単位の指定は避ける。
なぜなら、スケールするとその分増えてしまう。
細かい単位での指定が必要。
例えばセール実施中の国は優先度を高くする。
寝ている時間の国の優先度を下げる

認証処理ではbCryptを使うが、これは時間がかかりブロックが発生する。
ReactiveのSpringSecurityはこの処理を別スレッドで行う。

リアクティブの世界の場合、リクエストを受け付けたスレッドと応答を返すスレッドが異なる場合がある。
受け付けたリクエストに対する処理がどのスレッドで行われているかは分からない。
しかし、リクエストではSecurityの情報が必要になる。
スレッドローカルは利用できないため、サブスクライブした処理の中でどこからでも参照できるSubscriberContextを利用する。

サービスは落ちることがある。
綺麗な形で落とし、外から見たら何も起こらなかったようにみせる。
ダウンしているのが分かっていれば、そのサービスを呼ぶ必要はない。
サーキットブレーカーを利用する。

サービスが10インスタンス立ち上がっていることがわかっていれば、どこのサービスを使えるかがわかる。
1つのサービスがダメでも他のところに送ればいいが、リトライ・タイムアウトのハンドリングが難しい。
なので最初からリクエストを全てのサービスに送るヘッジングという手法がある。
リクエストから同じ結果が帰ってくる場合に有効。
最初に応答が返ってきた物を有効にし、他のストリームはキャンセルする。

双方向の通信をするため、いろいろな仕組みがある。
gRPCはプロトコルバッファーという縛りがある。それに対応したコードは書きたくない。
websocketはセキュリティの問題がある。
さらにペイロードがテキストで多様なデータが飛び交うと難しい。

RsocketとActuatorを組み合わせることで、送信先インスタンスがビジーであれば他のインスタンスにリクエストを送る仕組みがある。
RsocketとSpringSecurityを組み合わせられるため、セキュリティの担保もできる。
ゲートウェイ経由でバックエンドのサービスと直接接続できる。
RSocketならポインタが残るため通信が切断されてもレジュームできる。
クライアントが多くなるほど、他の方式と比較してコストの効率がよくなる。