JMSの代わりにScalaのアクターに有利な設計上の決定は何ですか? に対する質問と回答をすでに読んでいます。
通常、私たちは既に何年も前から存在するメッセージングソリューションを使用します。ポイントツーポイント通信にはWebSphere MQやApache ActiveMQなどのJMS実装が使用され、マルチキャストメッセージングにはTibco Rendevousが使用されます。
これらは非常に安定しており、実績があり、高い可用性とパフォーマンスを提供します。それでも、構成とセットアップはAkkaよりもはるかに複雑に見えます。
前述の製品(WebSphere MQまたはActiveMQ)がこれまでに正常に使用されたいくつかのユースケースで、いつ、なぜAkkaを使用する必要がありますか?今後のプロジェクトで、WebSphere MQやTibco RVの代わりにAkkaの使用を検討する必要があるのはなぜですか?
そして、いつAkkaを避けるべきですか?他のソリューションと同じ高可用性とパフォーマンスを提供しますか?それとも、Akkaを他のメッセージングミドルウェアと比較するのも悪い考えですか?
また、JVM(Point-to-Point)、TibcoRV(マルチキャスト)、Akka以外にも検討すべきJVM環境に別のメッセージングソリューションがあるかもしれません。
まず、「古い」メッセージシステム(MQ)は実装が古くなっていますが、エンジニアリングの考え方は新しいtransactional persistent queuesです。 ScalaアクターとAkkaはおそらく新しい実装ですが、アクターの古い同時実行モデルに基づいて構築されています。
ただし、2つのモデルは、どちらもイベントメッセージベースであるため、実際には非常によく似ています。 RabbitMQ vs Akka に対する回答を参照してください。
JVM専用のコードを作成する場合は、おそらくAkkaが適しています。それ以外の場合は、RabbitMQを使用します。
また、あなたがScala開発者であれば、Akkaは簡単なはずです。ただし、AkkaのJavaバインディングはそれほどJavaっぽくないため、Scalaの型システムのためにキャストが必要です。
また、Javaでは、人々は通常、メッセージングのために行うことをお勧めする不変オブジェクトを作成しません。その結果、JavaでAkkaを使用して、スケーリングしない何かを誤って実行するのは非常に簡単です(メッセージに可変オブジェクトを使用し、奇妙なクロージャーコールバック状態に依存します)。 MQでは、メッセージは常に速度を犠牲にしてシリアル化されるため、これは問題になりません。 Akkaでは、通常はそうではありません。
また、Akkaは、大部分のMQよりも大量のコンシューマーで優れた拡張性を発揮します。これは、ほとんどのMQ(JMS、AMQP)クライアントでは、すべてのキュー接続にスレッドが必要であるためです。つまり、大量のキュー==永続的に実行される大量のスレッドです。これは主にクライアントの問題です。 ActiveMQ Apolloには、AMQPの問題を修正したとされるノンブロッキングディスパッチャーがあると思います。 RabbitMQクライアントには、複数のコンシューマーを組み合わせることができるチャネルがありますが、多数のコンシューマーがデッドロックまたは接続の停止を引き起こす可能性があるという問題が依然として存在するため、一般的にこの問題を回避するためにより多くのスレッドが追加されます。
とはいえ、 Akkaのリモート処理 はかなり新しく、おそらく従来のメッセージキューが提供する信頼性のあるメッセージ保証とQoSのすべてをまだ提供していません(しかし、それは日々変化しています)。また、一般的にピアツーピアですが、ほとんどのMQシステムが行うもの(つまり、単一障害点)であるサーバーツーピアをサポートすると思いますが、ピアツーピア(RabbitMQはサーバー-じっと見ます)。
最後にRabbitMQとAkkaは実際に良いペアを作ります。特にRabbitMQはメッセージの消費の処理を支援しないため、RabbitMQのラッパーとしてAkkaを使用できます。メッセージをローカルで(単一のJVMで)ルーティングします。
Akkaを選択する場合
システム例:インタラクティブなリアルタイムチャットシステム
MQを選択する場合
例のシステム:スケジュールされたトランザクションバッチ処理システム
関係するコメントに基づいて編集する
OPは Akka とMessage Queueの両方が処理できる分散処理に関係していると仮定しました。つまり、彼は 分散Akka について話していたと思います。 ローカルの並行性のためにAkkaを使用することは、ほとんどのメッセージキューとのリンゴとオレンジの比較です。 Reactor ライブラリと simple-react の両方が実行する同時実行モデル(トピック、キュー、交換)としてメッセージキューモデルをローカルに適用できるため、私が最も言います。
低レイテンシアプリケーションでは、適切な同時実行モデル/ライブラリを選択することが非常に重要です。メッセージルーティングなどの分散処理ソリューションは、一般的に理想的ではありません。ほとんどの場合、ルーティングはネットワーク上で行われ、アプリケーション内より明らかに遅いため、Akkaが優れた選択肢です。ただし、独自のMQテクノロジーの中にはローカルルーティングを可能にするものもあると思います。また、前述したように、ほとんどのMQクライアントはスレッド化についてかなり愚かであり、非ブロッキングIOに依存せず、接続/キュー/チャネルごとにスレッドを持っています...皮肉なことに非ブロッキングioは常に低いとは限りませんレイテンシーですが、一般にリソース効率が高くなります。
ご覧のように、分散プログラミングと並行プログラミングのトピックはかなり大きく、毎日変化しているため、当初の意図は混乱せず、OPが懸念していた分散メッセージ処理の特定の領域に焦点を合わせていました。並行性の観点から、「リアクティブ」プログラミング(RFP /ストリーム)に検索の焦点を合わせたいと思うかもしれません。これは、「新しい」が、これらすべてのモデルを一般に組み合わせることができるアクターモデルおよびメッセージキューモデルに似たモデルですイベントベースです。
私はメッセージングシステムの専門家ではありませんが、アプリでAkkaと組み合わせて、両方の長所を活用できます。 Akkaとメッセージングシステム(この場合はZeroMQ)の実験に役立つ例があります。
Akka-Camelは、ZeroMQよりも良い例です。ZeroMQは、tcpからtcpへの直接通信です(したがってゼロ-メッセージキューはありません)。
AkkaCamelを使用すると、キューを抽象化し、メッセージキューメッセージのプッシュ/プルを処理するコードなしで、アクターから直接メッセージを生成/消費できます。
Akka-zeromqを放棄して、リモートでAkkaを直接使用できます。 akka-zeromqはコアライブラリから削除されていると思いますが、scala-zeromq( https://github.com/mDialog/scala-zeromq )と呼ばれるakka用の適切なzeromqライブラリを構築しました。
Akkaには、いくつかの主要なコアユースケースがあります。
1)可変状態
共有状態をアクターに非表示にすることで、共有状態を簡単に処理できます。アクターはメッセージを同期的に処理するため、アクターで状態を保持し、アクターAPIを介してそのフィールドを高い整合性で公開できます。
2)配布
Akkaでは同時実行は無料であるため、実際には配布の問題を解決することだと言います。マシンおよびコア全体に分散。 Akkaには、ネットワーク経由でメッセージを送信するための「ロケーションの透過性」が組み込まれています。単一のサービスをスケールアップするためのクラスタリングとパターンも関連付けられています。これにより、配信に非常に優れたソリューションになります(マイクロサービスアーキテクチャなど)
Akka-CamelでActiveMQでAkkaを使用する例(Java8を使用)
import akka.actor.Props;
import akka.camel.Camel;
import akka.camel.CamelExtension;
import akka.testkit.TestActorRef;
import akka.testkit.TestProbe;
import org.junit.Ignore;
import org.junit.Test;
import akka.camel.javaapi.UntypedProducerActor;
import akka.camel.javaapi.UntypedConsumerActor;
import static com.rogers.totes.TotesTestFixtures.*;
import org.Apache.activemq.camel.component.*;
public class MessagingTest {
@Test @Ignore
public void itShouldStoreAMessage() throws Exception{
String amqUrl = "nio://localhost:61616";
Camel camel = (Camel) CamelExtension.apply(system);
camel.context().addComponent("activemq", ActiveMQComponent.activeMQComponent(amqUrl));
TestProbe probe = TestProbe.apply(system);
TestActorRef producer = TestActorRef.create(system, Props.create((Producer.class)));
TestActorRef consumer = TestActorRef.create(system, Props.create((Consumer.class)));
producer.tell("Produce", probe.ref());
Thread.sleep(1000);
}
}
class Producer extends UntypedProducerActor{
@Override
public String getEndpointUri() {
return "activemq:foo.bar";
}
}
class Consumer extends UntypedConsumerActor{
@Override
public String getEndpointUri() {
return "activemq:foo.bar";
}
@Override
public void onReceive(Object message) throws Exception {
System.out.println("GOT A MESSAGE!" + message);
}
}