68
並行処理初心者のための Akka入門 株式会社ドワンゴ 吉村総一郎 @sifue

並行処理初心者のためのAkka入門

Embed Size (px)

DESCRIPTION

Concurrent programing explanation for akka beginers. 並行処理初心者のためのAkka入門 akka meetup 2014/09/28(日) http://connpass.com/event/8622/ このイベントの導入説明のために書かれました。 内容には、並行処理、アクターモデル、Akkaの機能の説明となっています。

Citation preview

Page 1: 並行処理初心者のためのAkka入門

並行処理初心者のためのAkka入門

株式会社ドワンゴ 吉村総一郎@sifue

Page 2: 並行処理初心者のためのAkka入門

今日はAkkaの勉強会

Page 3: 並行処理初心者のためのAkka入門

そもそもAkkaとは何か?

Page 4: 並行処理初心者のためのAkka入門

そんな人のためのプレセッション

Page 5: 並行処理初心者のためのAkka入門

Akkaとは• ScalaとJavaのApach2ライセンスで提供され

ているOSSのライブラリ

• アクターモデルを適用したスケーラビリティや耐障害性に優れた並行処理が書けるライブラリ

• Play Framework 2でも利用されている

http://akka.io/

Page 6: 並行処理初心者のためのAkka入門

Akkaを知る前に

•並行処理•アクターモデル

この二つを知らないといけない。今から上記二つをざっくり説明して、Akkaの機能もざっくり解説する

Page 7: 並行処理初心者のためのAkka入門

並行処理プログラミングとは

•この本の内容をざっくり•まだ書店にはあるかも?

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

ブライアン・ゲーツダグ・リー

Page 8: 並行処理初心者のためのAkka入門

並行処理の歴史1. OSのプロセスによる並行処理

• 資源の有効利用: 入出力のような外部操作の待ち時間

• 公平性: 複数のユーザーで複数の処理

• 利便性: 一つのプログラムで一つのタスクの方がシンプル

➡タイムシェアリングシステムでメモリは別

2. スレッド (軽量プロセス)による並行処理

• プロセスと同じ動機

• ひとつのプロセス内で複数のお仕事

• メモリ、ファイルハンドルは共有

• 共有データへのアクセスは明示的な同期化が必要

Page 9: 並行処理初心者のためのAkka入門

スレッドの利点•マルチプロセッサの有効利用• 1つのスレッドに1つのタスクで設計の単純化※

•サーバーへのクライアント接続などの処理を単純化※

•応答性の良いUIの実現※問題点でもある

Page 10: 並行処理初心者のためのAkka入門

スレッドのリスク: 安全性の危機

インクリメントと取得が別スレッドで交互に実行

p.7より

Page 11: 並行処理初心者のためのAkka入門

スレッドのリスク: デッドロック

リソースをロックし合って永遠に待つ

パターン

p.233より

Page 12: 並行処理初心者のためのAkka入門

スレッドのリスク: 実行性能の危機

•スレッドが増えると、プロセス上のスレッドの入れ替えのためのコンテキストスイッチのコストが増大

Page 13: 並行処理初心者のためのAkka入門

スレッドセーフの解決案1.ステートレスにする

2.ロックして同期化処理を行う

• メモリの可視性にはすごく注意が必要 (激難)

変数の更新が別スレッドからは見えない

p.40より

Page 14: 並行処理初心者のためのAkka入門

オブジェクトの共有の難しさ

• synchronizedによるlockでの同期• volatileによる揮発性変数の利用•ただし同一スレッドからの書き込みのみの場合に限る

•同期化されてない内部変数を逸出しないような入念なチェックが必要

Page 15: 並行処理初心者のためのAkka入門

並行処理プログラミングってとてもむずかしい...

→ concurrentパッケージのお陰でなんとか

Page 16: 並行処理初心者のためのAkka入門

ちなみにJavaのconcurrentパッケージの概要

名前 内容Executor フレームワーク スレッドを、CallableとFutureで扱えるようにしたり、

並列度やリトライ、スケジュールを制御できる

Concurrent コレクション Javaのコレクションをマルチスレッドで扱えるようにしたコレクション群、putIfAbsentとかもある。

Atomic パッケージ AtomicLongやAtomicReferenceなど、並行処理で変更しても問題が起こらない値や参照のクラス群

ReentrantLock 再利用可能なロック。いわゆる排他処理とかMutexとかいわれるものを実現。tryLockとlockの両対応。

CyclicBarrier 全スレッドがバリアに到達するまで待って、何かを実行してくれる部品

CountDownLatch 指定した数まで処理が実行されるまで、全スレッドを待たせてくれる部品

Semaphore 一度に指定された数のスレッドしか実行されないようにしてくれる部品

DelayQueue 特定の時間が経過すると中身を取得できるようになるキュー

Page 17: 並行処理初心者のためのAkka入門

とはいえ、チーム開発してるとよくわからんバグが起こりやすい

→ なぜかテストが2回に1回落ちるw

Page 18: 並行処理初心者のためのAkka入門

誰かが界王拳みたいなものだと言ってた

(数倍の力出るけど死ぬかもしれない...)

Page 19: 並行処理初心者のためのAkka入門

そこで登場

Page 20: 並行処理初心者のためのAkka入門

アクターモデル

Page 21: 並行処理初心者のためのAkka入門

アクターモデルの歴史

•将来的に「数百・数千のマイクロプロセッサから構成され、個々にローカルメモリを持ち、高性能通信ネットワークで通信を行う並列コンピュータが近い将来登場するとの予測」から開発された

Page 22: 並行処理初心者のためのAkka入門

現状スケールのためには

•マルチコア•クラスタ構成

が、今の大規模サービスの基本戦略なので、すごく今の現状にマッチ

1985年ぐらいにアクターモデル理論として完成したらしい…ここらへんの学術的な話は→ Wikipediaのアクターモデルを見てください

Page 23: 並行処理初心者のためのAkka入門

アクターモデルとは

アクター

メールボックス

メッセージ

address

address

address

address

address

address

ループ

Page 24: 並行処理初心者のためのAkka入門

アクターという処理行い、状態を持つオブジェクト

アクター

メールボックス

メッセージ

address

address

address

address

address

address

ループ

Page 25: 並行処理初心者のためのAkka入門

それぞれメールボックスとアドレスがある

アクター

メールボックス

メッセージ

address

address

address

address

address

address

ループ

Page 26: 並行処理初心者のためのAkka入門

アクター内ではループで逐次処理しながら、メッセージを別なアクターに投げたりして、メールボックスに溜まった命令を

順不同で処理 (Akkaではデフォルトでは到着順で処理)

アクター

メールボックス

メッセージ

address

address

address

address

address

address

ループ

Page 27: 並行処理初心者のためのAkka入門

メッセージパッシングすることで非同期に処理し、単一のループで逐次処理しているので、並行処理のロックや同期が不要

アクター

メールボックス

メッセージ

address

address

address

address

address

address

ループ

Page 28: 並行処理初心者のためのAkka入門

さらにAkkaでは、子どものActorを作り、それぞれにラウンドロビンでメッセージをブロードキャストしたりすることもできる

アクター

メールボックス

メッセージ

address

address

address

address

address

address

ループ

Page 29: 並行処理初心者のためのAkka入門

すばらしい!

アクター

メールボックス

メッセージ

address

address

address

address

address

address

ループ

Page 30: 並行処理初心者のためのAkka入門

Akka Actorの主な特徴• ActorSystemというActorの実行コンポーネントが内部的にスレッドプールを持っており、tellによるメッセージパッシングのイベント駆動モデルと、マルチスレッドによる実行の融合がなされている

•デフォルトでは、単一実行するMailboxの実装により逐次メッセージが処理される

Page 31: 並行処理初心者のためのAkka入門

Actor同士がリモートでメッセージを送信できる

• ActorPathというアドレスを利用•ロケーション透過性があり、アクターの物理的な位置をAkka上では考慮する必要が無い

•ポートは自由に設定可能

Page 32: 並行処理初心者のためのAkka入門

耐障害性の機能• SupervisorがActorを監視しており、処理中

に例外を吐いた時に再実行を行わせたりすることができる

• SupervisorStrategyにより子どものアクターが起こしたエラーの挙動を変えられる

• let-it-crashという考え (とっとと壊して新しいモノを再度作ったり、やり直したりする)

Page 33: 並行処理初心者のためのAkka入門

Akkaで実現できる機能• 並行処理

• 分散処理のために子どものアクターを作る

• アクターが失敗した時に再実行する

• アクターのメッセージの結果をFutureで受け取る (ask)

• メッセージの送信元を知る

• メッセージ送信のスケジューリング

• リモートのアクターへのメッセージ送信

• アクター同士のゴシッププロトコルによるクラスタリング

• トランザクションの実行とロールバック

• ロギング

Page 34: 並行処理初心者のためのAkka入門

どんな用途に向いているか• トランザクション処理

• サービスのバックエンド処理

• 並行処理

• 大規模なシミュレーション計算

• バッチ処理

• コミュニケーションハブ

• オンラインゲーム、賭けなどの実装

• BIやデータマイニング

• 複雑なイベントストリーム処理

スケールアップ、スケールアウト、耐障害性の必要な

http://doc.akka.io/docs/akka/2.3.6/intro/use-cases.html

Page 35: 並行処理初心者のためのAkka入門

Akkaの基本的な機能の解説• Actor

• ActorSystem

• tell, ask

• SupervisorStrategy

• ActorPath

• DeadLetter

• Akka Cluster

Page 36: 並行処理初心者のためのAkka入門

Actor• メッセージを受信するためのMailboxと、メッ

セージの対する処理を記述するreceiveを持つ

• それぞれのActorは、並列に動作するが、1つのActorは並列にメッセージを処理することはない

• そのため、Actorでスレッドセーフを意識する必要はない

Page 37: 並行処理初心者のためのAkka入門

HelloWorld• Actorにメッセージを送信して表示する

Page 38: 並行処理初心者のためのAkka入門

ActorSystem

•複数のActorを構成するために必要なもろもろを管理するクラス

• ActorSystemからActorを作っていくことができる

Page 39: 並行処理初心者のためのAkka入門

tell, ask

• Actorにメッセージを送信する

Page 40: 並行処理初心者のためのAkka入門

tell (別名: “!”)• Actorにメッセージを投げて、返答を待たない

Page 41: 並行処理初心者のためのAkka入門

ask (別名: “?”)• Actorにメッセージを投げて、返答を待つ

ブロッキングするのではなく、Futureオブジェクトが返る

Page 42: 並行処理初心者のためのAkka入門

SupervisorStrategy• Actorは複数の子供Actorを持つことができる

http://doc.akka.io/docs/akka/snapshot/scala/fault-tolerance.html

Page 43: 並行処理初心者のためのAkka入門

親Actor• 子供Actorを管理するための戦略、SupervisorStrategyを持つことができる

• 自分で定義することもできるがすでに2つ定義されている1. OneForOneStrategy

- ある子供Actorが例外で停止した時、その子供Actorだけを再起動する

2. OneForAllStrategy

- ある子供Actorが例外で停止した時、全ての子供Actorを再起動する

Page 44: 並行処理初心者のためのAkka入門

SupervisorStrategyの設定の例

Page 45: 並行処理初心者のためのAkka入門

ActorPath• ActorにはURIが付いており、それでメッセージを送信できる

akka://system/user/MyActor

Page 46: 並行処理初心者のためのAkka入門

ActorPathはActorの親子関係に対応

•MySupervisorがMyActorという子供Actorを持っている場合

akka://system/user/MySupervisor/MyActor

Page 47: 並行処理初心者のためのAkka入門

ActorPathからActorにメッセージを投げる

Page 48: 並行処理初心者のためのAkka入門

存在しないAcotorにメッセージを投げたらどうなるの?

• DeadLetterになる

Page 49: 並行処理初心者のためのAkka入門

DeadLetter• メッセージを投げたけど届かなかった場合

にメッセージはDeadLetterとなる

• 以下の場合もDeadLetterになる

- 送信したがActorが停止してしまった場合

- Actorが持つメールボックス(メッセージの入れ物)に追加できなかった場合

‣ 容量制限に引っかかるなど

Page 50: 並行処理初心者のためのAkka入門

Akka Cluster• Akka Remoteを利用した、複数ノード構成

のAkkaアプリケーションを構築するエクステンション

• ノードのメンバー管理、クラスタへのノードのJoin・Leaveを行ってくれている

• 参加のやりとりはゴシッププロトコル

• 論理時間はベクタークロックアルゴリズム

Page 51: 並行処理初心者のためのAkka入門

ノードの役割• シードノード

- 最初にクラスタに参加するノードが接続するためのエントリーポイント

• リーダー

- クラスタを管理するノード、リーダーがクラスタから落ちると別のノードがリーダーに昇格する

• ロール

- 各ノードに複数のロールを持たせることができる (ただの文字列)

Page 52: 並行処理初心者のためのAkka入門

ノードの一生•クラスタにJoinしてLeaveするまでのライフサイクルが存在する

Page 53: 並行処理初心者のためのAkka入門

ノードの状態•ノードは一生の中でいくつかの状態を取る•この状態の管理はリーダーノードが行い、クラスタ全体で共有される

状態 意味joining クラスタに入ろうとしているup クラスタに正常に入った状態

leaving/exiting クラスタから正常に抜けようとしてる状態down ノードが落ちた状態removed クラスタから削除された

Page 54: 並行処理初心者のためのAkka入門

Unreachable

•特別な状態、あるノードが通信不能、 ハートビートがタイムアウトした時など

•この状態はdown状態と似ているが、クラスタ全体で共有されるわけではなくノードごとに保持している

Page 55: 並行処理初心者のためのAkka入門

Unreachableの検出•任意のノードがUnreachableかどうかは、ノードのFailureDetector(*fd)と呼ばれる仕組みにより検出される

•他のノードからはUnreachableではなくとも、自分からはUnreachableであることもある

Page 56: 並行処理初心者のためのAkka入門

利用する時に気をつけること

• ActorSystemをたくさん作らない

• メッセージに型がない

• シリアライズ不可能なメッセージを投げない

• DeadLetterに注意する

• Mailboxのサイズに注意する

• ActorPathに注意する

Page 57: 並行処理初心者のためのAkka入門

ActorSystemをたくさん作らない

• スレッドプールができるので生成コストが大きい

• ちなみに、以下の2つのActorSystemは同値ではないので要注意

Page 58: 並行処理初心者のためのAkka入門

シリアライズ不可能なメッセージを投げない• Actorはノードをまたいで実行される時もある

•シリアライズ不可能なクラスのインスタンスを投げないこと

➡例外投げて落ちる

Page 59: 並行処理初心者のためのAkka入門

メッセージに型がない• Actorが受け取る事のできるメッセージは全部Any

• TypedActorというものもあったりするが基本、メッセージ型を作ったほうが便利

• Actorが処理することができないメッセージを投げても、Actorに無視されるだけ

➡DeadLetterにならない

➡Unhandledになる、Loggerで拾うことは可能

Page 60: 並行処理初心者のためのAkka入門

DeadLetterに注意する• Actorに処理して欲しいはずなのに処理してもらっていない

• DeadLetterをログに全て出力しているの設定を確認する

•何個まで出すかなどの設定があるhttp://doc.akka.io/docs/akka/2.3.4/scala/logging.html

Page 61: 並行処理初心者のためのAkka入門

MailBoxのサイズに注意する

•メッセージが無限に入るので処理が遅れてることに気がつかない

•対策としては、Mailboxにサイズ制限を設ける

•デフォルトでは無制限

Page 62: 並行処理初心者のためのAkka入門

ActorPathに注意する

•メッセージを投げたいActorの実装が変わってActorPathが変わるかもしれない

•対策としては、ActorPathのBuilderクラスを用意したほうが無難

Page 63: 並行処理初心者のためのAkka入門

もっとAkkaについて知りたい

• akka-user、akka-devを見る• akkaのコードを読む (https://github.com/akka/akka)

• Effective Akkaという洋書がKindleで読める

Page 64: 並行処理初心者のためのAkka入門

以上ご静聴ありがとうございました

Special thanks for @suikwasha (Shoshi TAMAKI)

Page 65: 並行処理初心者のためのAkka入門

おまけ

Page 66: 並行処理初心者のためのAkka入門

Akka Streamsについて

• 2014年9月現在実験的機能として公開中• Akkaの分散、耐障害性の仕組みを利用してストリーム処理ができる

Page 67: 並行処理初心者のためのAkka入門

Akka Streamsの用途

•バルクデータの転送•リアルタイムデータソース•巨大データセットのバッチ処理•監視/解析

http://www.slideshare.net/rolandkuhn/reactive-streams

Page 68: 並行処理初心者のためのAkka入門

Akka StreamsでのFlowの処理例

http://typesafe.com/activator/template/akka-stream-scala

• データをストリームとして処理

• Flowの情報受取元はTCPを選択することもできる