akka / erlangでアクターを使用するのが良くないのはいつですか?


58

私はakkaで毎日7〜8か月働いています。私が始めたとき、私はアプリケーションに取り組んでおり、ほとんどのオブジェクト間で通信するために、アクターは基本的にアクターシステム内のどこででも使用されることに気付きました。だから私は同じことをした-x / y / zの別のアクターをスピンアップする。

これはあまりにも無差別で、必要のないところに複雑さを加えているように思えます-しかし、アクターとプレーンを介した同期、または先物を介した非同期ロジックを使用する必要がある場所についての議論は見つかりません。同僚が似たようなことを言った後、私は自分のスタンスを熟考し始めました。最近、タスクを熟考し、不変の実装で同じ結果を安全に達成できるため、別のアクターの作成を避けたいくつかのケースを実現しました。たとえば、非常に頻繁にアクセスするデータベースまたはファイルから設定値を取得するようなものです結果を待つのが実際のユースケースです。

特に、不変の状態で遊んでいる場合、アクターは複雑さを生み出し、スループットを制限します。たとえば、オブジェクトの純粋な関数は、並行性のレベルを問わず、リスクなしで同時に呼び出すことができます。アクターは一度に1つのメッセージしか処理できません。別の考慮事項は、futureの使用を開始しない限り、結果を待つ必要がある場合にスレッドを保留することですが、非同期メッセージングやスケールを心配する必要がない場合は、アクターを採用するのはやり過ぎかもしれません。

だから私の質問は-俳優を使用するのに悪い時間はありますか?アーランがどのように見えるのか興味があり、他の人の洞察が本当に欲しいです。または、アクターの使用に関するいくつかの原則がある場合。


Akkaと毎日何ヶ月も働く機会はどのような仕事にありますか?
デン14年

3
良いもの。:)または自分で変更を加えます。
JasonG 14年

ask俳優をプレイすることとプレーンを使用することとのトレードオフが具体的に知りたいと思い Futureます。
マックスハイバー

2
数年後、私はAkkaについての本を書くことになりました。次のように要約できると思います。たとえば、カウンターなどの状態がある場合、複数のスレッドがその値を読み書きします。同期およびロックなし。その状態をアクター内に置くと、突然アクセスが安全になり、書き込みをドロップしたり、古い読み取りを取得したりすることがなくなります。アーランとアッカのアクターは、状態が悪くなり、アクターがエラーをスローする可能性があると想定しているため、自己回復システムの特性があります。突然変異する必要がない場合、先物はより単純です
JasonG

多くの年後、私はアーラン/エリキシルプログラマーだと私は:)新しい洞察バックこれまでくるあなたが必要なときにプロセスが必ず組み込まれているので、プロセスの代替としてオブジェクトがないとエリクサーがかなり異なっている状態で。それはたまたま並行的です。これはまだ最高のヒューリスティックです。
ジェイソンG

回答:


23

これは私が興味を持っている質問であり、私はいくつかの研究を行ってきました。他の視点については、Noel Walshによるこのブログ投稿またはStack Overflowに関するこの質問を参照してください。私が提供したい意見があります:

  • Akkaはメッセージを処理するため、「プッシュマインドセット」を促進すると思います。多くの場合、並行性のために、これはあなたが望むものではないと主張します。プルははるかに安全です。たとえば、分散システムの一般的なパターンの1つは、キュー内の情報を処理するワーカーのセットです。Akkaでこれが可能であることは明らかですが、人々が試みる最初のアプローチであるとは限りません。Akkaは耐久性のあるメールボックスも提供しますが、その使用方法によって異なります。単一の共有キューは、作業の分散/再割り当てのためにワーカーキューごとよりもはるかに柔軟です。
  • クラスをアクターに置き換えるという考え方に簡単に入ります。実際、一部の人々は、俳優はただ一つのことをするべきだと言って、それを主張しているようです。すべてのクラスがアクターである場合、それは多くの余分なメッセージと受信/送信ブロックであるため、Jasonが説明するように、これは論理的な結論に達すると、コードの複雑さが増します。また、インターフェイスの形式が失われるため、コードの理解とテストが難しくなります。コメントがこれの解決策であるとは確信していません。また、Akkaの伝説的な効率性にもかかわらず、アクターの増殖はパフォーマンス上賢明なアイデアではないと思います。Javaスレッドを使用する場合、それらは貴重であり、それに応じて保存されることがわかります。
  • これは前のポイントに関連していますが、もう1つの面倒な点は、NoelとPinoが強調している型情報の損失です。これにはいくつかの方法がありますが、それらは非標準推奨されていない、または実験的なものです。
  • 最後に、「クラッシュさせる」という考え方があったとしても、並行性は困難です。代替のプログラミングモデルは役立ちますが、問題を解決することはありません-それらを変更します- それが正式にそれらについて考えるのが良い理由です。また、Joe Averageの開発者がRabbitMQ、Storm、Hadoop、Spark、Kafka、NoSQLデータベースなどの既製のツールに手を伸ばす理由でもあります。Akkaにはあらかじめ構築されたツールとコンポーネントがありますが、それは非常に低レベルであると感じられるため、分散システムの一般的な要素をより簡単に構築することで、開発者はシステムを正しく構築できます。

ジェイソンのように、私はここで他の人の洞察を聞きたいです。上記の問題のいくつかに対処し、Akkaをよりよく使用するにはどうすればよいですか?


1
私はテストに関するこの投稿をtimgilbert.wordpress.com/2013/07/07/の
マークバトラー

「継承を介した構成」は、依存性注入に依然として有用です。たとえば、依存関係をプロパティとして渡します(コンストラクターのパラメーターを使用)。その場合、問題は監督になります。作成されたアクターは、アクター以外の場所で監督されます。ルーターを使用して、トップレベルで作成されたアクターを監督する戦略をラップすることもできますが、それは今ではかなり複雑です!ケーキがより良い解決策になると思います-たとえば、dbサービスアクターのアクター作成に特徴があります。次に、テキストコンテキストでテストモック/スタブdbサービス特性を使用します。
JasonG 14年

1
はい、正確に-監視は依存性注入ではうまく機能しません。また、クラスではなくファクトリーをインジェクトする必要がある場合もありました。そうしないと、奇妙なクロージャーの問題が発生しました-Akkaのスレッドの処理のためだと思います。
マークバトラー14年

私はそれは悪い考えではないと思います-感謝の印-私は実際にこれについて少し書いて、それを社交しようとするかもしれません。おそらく小道具を与える何かを注入できますか?消費者がアクターをインスタンス化できるようなアクターファクトリー。例えば、def method(arg)= return(psuedo?)ファクトリーからProps(new ActorWithArgs(arg))を返すので、適切なコンテキストでアクターを作成できます。これは、diのケーキソリューションの良いアイデアであり、良いターゲットのようです。
ジェイソンG 14年

私はこのコースを始めたばかりです。coursera.org/ course / posa主にAndroidをプログラミングする人を対象としていますが、Javaでの並行性の概要も説明しています。私が疑問に思っていることの1つは、「Akkaは単なるイベントループであり、イベントループをさまざまなスレッドに配置できるためです。」
マークバトラー

21

アクターモデルの用途を検討する価値があります。アクターモデルは

  1. 並行性モデル
  2. 可変状態への同時アクセスを回避します
  3. 非同期通信メカニズムを使用して並行性を提供します。

特に、同期状態を維持する必要がある共有状態の異なるコンポーネント間に関係がある場合、複数のスレッドから共有状態を使用することは非常に難しくなるため、これは有益です。ただし、次のドメインコンポーネントがある場合:

  • 並行性を許可しない、または
  • 可変状態(関数型プログラミングなど)を許可しない、または
  • 同期通信メカニズムに依存する必要がありますが、

その場合、アクターモデルは(もしあれば)多くの利点を提供しません。

お役に立てば幸いです。


ありがとう-私はあなたが本当に2つのことを評価する必要があると思います-可変状態と並行性?クラスがステートレスまたは同時ではない場合、解決する問題はありません。もう1つの考慮事項-フォールトトレランスは別のポイントだと思いますか?例えば、不変のredisクライアントを持っているが、実行中に失敗する可能性がある場合-それは良いユースケースではないでしょうか?そのアクターを再起動する必要があるかもしれませんか?As-クラスは純粋に不変である可能性がありますが、不変のアクタの外部で破損状態が発生し、それが失敗する可能性が非常に高いです。
JasonG

redisとの通信を担当するアクターは例外を取得して再起動すると思います。
ジェイソンG

@JasonG私の考えでは、「フォールトトレランス」は一般的にアクターモデルの側面ではありません。これは、Erlang(およびAkka?)でのアクターモデルの実装に伴うものです。私はredisと話すことができませんが、「不変のクライアント」は奇妙に聞こえます...ソフトウェアコンポーネントが失敗する可能性がある場合、不変と見なされる方法がわかりません。
エイダンカリー

akkaにはフォールトトレランスと監視があり、アーランと非常によく似ています。不変のクライアントについてあなたが言っていることは理解していますが、不変とはコードの状態がどこでも変わらないことを意味します。起動時に接続を初期化すると、クライアントコードは、あらゆる種類の障害で使用される再起動戦略で不変になり、問題が発生したときにアクタを再初期化することができます。
JasonG

12

あなたの直感は正しいです、私見。どこでも俳優を使用することは、ことわざのハンマーを持って釘だけを見るようなものです。

Erlangのベストプラクティスは、同時に発生するすべてのアクティビティにプロセス/アクターを使用することです。つまり、実際の生活と同じです。適切な粒度を見つけるのが難しい場合もありますが、ほとんどの場合、モデル化されたドメインを見て、少し常識を使って知るだけです。私はそれよりも良い方法はないのではないかと心配していますが、それが役立つことを願っています。


よろしくお願いします。この議論で何が起こるのか、本当に興味があります。
JasonG

0

入出力メッセージの順序:

私は最近、アクターモデルが実際に同時実行の問題を引き起こしたakkaベースのアプリケーションに出会いました。負荷がかかった場合は、より単純なモデルで十分でした。

問題は、着信メッセージが(異なるアクターパスを介して)異なる「レーン」で移動しているが、コードは、メッセージが到着した順序と同じ順序で最終宛先に到着すると想定したことです。データが十分に長い間隔で到着する限り、これは機能します。これは、宛先に競合する競合するメッセージが1つしかないためです。間隔が短くなったとき、彼らは順不同で到着し始め、奇妙な行動を引き起こしました。

問題は少し少ないアクターで正しく解決できたかもしれませんが、それらを使いすぎた場合に犯すのは簡単な間違いです。


これは基本的であり、広く関連しています。2つのアクター間の順序のみを保証できます。doc.akka.io/docs/akka/current/scala/general/… ファンアウト/インするどのシステムでも注文の配送を保証することはできません。andreasohlund.net/2012/01/18/dont-assume-message-ordering
JasonG

-1

私の意見では、アクターには2つのユースケースがあります。ポートなどの共有リソース、および大規模な状態。最初のものはこれまでの議論で十分にカバーされてきましたが、大きな状態も正当な理由です。

すべてのプロシージャ呼び出しで渡される大きな構造体は、多くのスタックを使用できます。この状態を別のプロセスに入れ、構造をプロセスIDに置き換え、そのプロセスを必要に応じて照会できます。

mnesiaなどのデータベースは、クエリプロセスの外部に状態を保存していると考えることができます。


1
明確にできますか?ネットワーク全体で大きな状態を意味しますか?ローカルプロセス内で、不変構造への参照を渡すことはほとんどコストがかからず、可変構造を渡すことはできません。あなたが送信するためにコピーする必要がある大きな可変構造について話していると仮定しますか?基本的に同じことです-共有状態。サイズは実際には何も変わりません。誤解している場合は教えてください。
JasonG

それでは、どのように参照渡ししますか?確かにそれを行う方法は、構造体をプロセスに入れてprocessidを渡すことです。ローカル呼び出しはデータをスタックに配置し、すべての再帰呼び出しはそれを再度行います(末尾再帰を除く)。構造の再帰処理は、ある呼び出しから別の呼び出しに状態を転送するためのリストを使用して実行でき、この状態は他のプロセスで構造を参照できます。
トニーウォレス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.