この記事はJavaの基本的な知識を持つ人のためのものです。
Akka は、Java および Scala 向けに、高度な並行性、分散性、耐障害性を備えたメッセージ駆動型アプリケーションを構築するためのツールキットです。
パワージョブ :
https://github.com/PowerJob
I. 俳優モデル
アクター・モデルは、1973年にカール・ヒューイット、ピーター・ビショップ、リチャード・スタイガーの論文で紹介され、現在では並行計算を理論的に理解するためのフレームワークとして、また並行システムの実用的な実装の基礎として使用されています。
アクターはメッセージを受信すると、意思決定を行い、さらにアクターを作成し、さらにメッセージを送信し、次のメッセージをどうするかを決定することができます。アクターは自分自身のプライベートな状態を変更できますが、メッセージを通じて間接的にしか変更できません。
各アクターは、ステート、ビヘイビア、メールボックスの3つの部分で構成されています:
- 状態:Actorにおける状態とは、Actorオブジェクトの変数情報を指し、状態はActor自身が管理するため、並行環境におけるロックやメモリの原子性の問題を回避することができます。
- ビヘイビア(Behaviour):アクターが受信したメッセージによってアクターの状態を変更する、アクター内の計算ロジック。
- メールボックス:メールボックスは、アクターとアクターの間の通信の橋渡し役です。メールボックスは、FIFOメッセージキューを通して送信側のアクターのメッセージを内部に保存し、受信側のアクターはメールボックスのキューからメッセージを受け取ります。
以前は、曖昧な概念の全体の多くを言った、私たちはすべての雲を読んでいると信じています。ここでは、いくつかの単語を言うために専門用語の私自身の理解と組み合わせる:実際には、Actorのモデルの設計思想は、イベント駆動型であり、単純にスレッドレベルのメッセージミドルウェアとして理解することができます。すべてのActorは、唯一のメッセージ通信を介して、データを共有しないので、セキュリティの問題を並行処理の伝統的な並行プログラミングプロセスを気にする必要はありません。同時に、Actorの下部の軽量設計のおかげで、1つのマシンが数百万のActorに存在することができますので、優れた並行処理性能をもたらすことができます。
また、アクターモデルではすべてがアクターなので、当然分散されます。つまり、異なるマシン間のアクター通信とローカルアクター間の通信に実質的な違いはありません。
したがって、イベント駆動型プログラミングの考え方とアクターモデルの使い方をマスターし、特定の実装フレームワークと組み合わせさえすれば、高性能な分散アプリケーションを簡単に書くことができます。
Akka ツールキット
Akka Toolkit は、JVM プラットフォーム上での Actor モデルの実装です。 Akka 自身が Actor モデルを完全にサポートしており、並行/並列プログラムのためのシンプルで高レベルな抽象化、非同期、ノンブロッキング、高性能なイベント駆動プログラミングモデル、非常に軽量なイベント駆動処理などを提供します。同時に、"ツールキット "として、Akkaはまた、多くの追加機能を提供しています、スペースの制限のために、ここではいくつかのパッケージの簡単な紹介です、あなたは〜についての詳細を学ぶことに興味がある公式サイトに行くことができます。
akka-streams: 非同期、ノンブロッキングの背圧ストリーム処理を実行する直感的で安全な方法を提供するストリーム処理コンポーネント。
akka-http: HTTP コンポーネント。モダンで高速、非同期、ストリーミングファーストの HTTP サーバーおよびクライアントです。
akka-cluster: クラスターメンバー管理、エラスティック・ルーティングなどのクラスターコンポーネント。
akka-remote(artery-remoting):通信コンポーネントは、PowerJobで使用されるコアコンポーネントでもありますが、公式ウェブサイトでは、通常の分散アプリケーションの直接使用を推奨していませんクラスタの直接使用をお勧めします。
akka-persistence: メッセージの確実な配信を保証するために「最低一度は配信する」機能を提供する永続コンポーネント。
アッカの簡単な使い方
このチュートリアルはPowerJobで使用される全てのAPIをカバーしています。つまり、この部分を理解すれば、ソースコードの中のAkkaはもう怖くありません!
3.1 役者の育成
まず最初に、バージョン 2.6 以降、Akka は classic と typed と呼ばれる 2 つの API を提供していることに触れておきましょう。各 Actor が扱うメッセージのタイプはパラダイムによって直接指定できるため、バグが制限されます。しかし、扱うメッセージが無数にある複雑なシステムの場合、強い型付けによって Actor が扱うメッセージのタイプは 1 つだけに制限されます。これは論理的には明確ですが、実際には読みにくいコードや緩い構造につながります。ここまで説明して、ようやく本題に入りますが、著者はクラシックを好んでいるので、PowerJobはAKKAクラシックAPIのみを使用しています。
先ほども申し上げたように、Actorモデルを最もシンプルに理解する方法は、メッセージミドルウェアであり、その本質はイベントドリブン、つまりメッセージを受け取って処理することだと思います。Actorの本質はイベントドリブン、つまりメッセージを受け取って処理することです。 プログラミングに反映させると、Actorの開発もコンシューマ向けメッセージミドルウェアの開発と似ていて、インターフェイスを変えて少し機能を増やしただけです。
それでは、コードをご覧ください:
public class FriendActor extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(Ping.class, this::onReceivePing)
.matchAny(obj -> log.warn("unknown request: {}.", obj))
.build();
}
private void onReceivePing(Ping ping) {
getSender().tell(AskResponse.succeed(null), getSelf());
}
}
まず最初に行うべきことは、当然ながら新しいクラスを作成し、AbstractActorというインターフェースを実装することです。AbstractActorでは、createReceiveメソッドをオーバーライドする必要があり、その戻り値としてReceiveオブジェクトが必要になります。開発者にとって必要なことは、このReceiveオブジェクトを構築することです。つまり、Actorがどのようなメッセージを受信したときにどのような処理を行うかを示すことです。
3.2 ActorSystemの初期化
メッセージ処理 "ロール "としてアクターは、工場の労働者のように、各人が自分の任務を持って、タスクを完了するために指示を受信する専用。現実の労働者が工場によって組織化され、管理される必要があるように、アクターもまた独自の工場-ActorSystem-を必要とします。このため、アクターを作成するには、まずActorSystemを作成する必要があります。
PowerJob は以下のメソッドを使用して ActorSystem を作成します。最初のパラメータは ActorSystem の名前を指定し、2 番目のパラメータは作業ポート、シリアライズ方法、ロギングレベルなど、ActorSystem が使用する構成情報を渡します。
actorSystem = ActorSystem.create('powerjob-server', akkaConfig);
ActorSystem "factory "の作成が完了したら、正式にActorの作成を開始します:
actorSystem.c(Props.create(FriendActor.obj), 'friend_actor');
最初のパラメータである Props は、アクターが作成されるときにオプションを指定するために使用される設定クラスです;
akka://powerjob-server/user/server_actor
2つ目のパラメータはActorの名前を指定します。 Actorの名前とそのActorSystemの名前を使用することで、パスを構築することができ、そのパスに従ってActorを簡単に見つけて通信を実現することができます。
3.3 情報の相互作用
ActorSystemの初期化とアクターの作成が完了したら、いよいよAkkaフレームワークを使用します。powerJobは、システム内の分散ノードと通信するためにAkkaフレームワークのリモートコンポーネントを使用します。
String actorPath = "akka://powerjob-server@192.168.1.1/user/friend_actor";
ActorSelection actorSelect = actorSystem.actorSelection(actorPath);
actorSelect.tell(startTaskReq, null);
他の通信方法と同様に、まずターゲットのアドレスを取得する必要があります。akka-remoteの構文に従って、ターゲットとなるActorの名前、ActorSystemの名前、ターゲットとなるマシンのアドレスを指定して通信用のURIを取得し、actorselection()メソッドを使用してActorselectionオブジェクトを取得します。URIを取得したら、actorselection()メソッドでActorselectionオブジェクトを取得し、tellメソッドを呼び出してターゲットActorにメッセージを送信します。
その後、慎重なパートナーは、なぜPowerJobは、基礎となる通信フレームワークとしてakka-remoteを使用する理由を尋ねなければならない、その最小限の通信APIを参照してくださいすることです、ここを参照してください、どのようにシンプルなああ見つかりませんでした。高レベルのパッケージングライブラリで、HTTPリクエストを送信すると、実際にはコードのほぼ3行ですが、あなたはAkkaの準備作業を使用することはまだそんなに、それは簡単だと言いましたか?ということで、以下では、最終的にakka-remoteがシンプル〜〜を見つけるためにあなたを取るでしょう!
まず、既存のプロトコルを選択せず、Nettyを使って独自のライブラリを構築する場合、サーバー、クライアント、リスナー、コーデックだけでも、かなりのコード量になります。HTTPのような既存のプロトコルを使う場合、送信できるコードは3行程度ですが、受信できるコードは3行をはるかに超えます。HTTPはHypertext Transfer Protocolとして知られており、送信されるのは当然シリアル化されたテキストデータなので、例外処理や失敗時のリトライなどの機能はもちろん、受信側でデコードやパースを行う必要があります。akka-remoteはどうですか?Actor のコードを見てわかるように、match メソッドの後に特定のクラスが続きます。つまり、Akka が自動的にデシリアライズを完了してくれるので、メッセージの受信側としては、余計なコードなしで本当にそれを使うことができます。同時に、例外処理もすべて Akka が行ってくれます。つまり、akka-remote を使用することで、データレシーバーを非常にシンプルにし、ロジックの実装だけに集中することができます。
第二に、分散環境では通信が一方向でないことがよくあります。特に PowerJob のような高可用性を追求するフレームワークでは、メッセージが配信されたことを確認するための応答メカニズムが必要になることがあります:
AskResponse response = new AskResponse(true, "success");
getSender().tell(response, getSelf());
getSender()メソッドを使えば、メッセージ送信者のActor参照オブジェクトを取得し、そのオブジェクトを通してメッセージに返信することができます。