12

Akka Cluster-Sharding は、Akka ノード全体でステートフルな永続アクターの単一インスタンスを作成する必要があるユース ケースとうまく一致しているようです。

それを構築するために引数を必要とする Entry アクター タイプを持つことが可能かどうかはわかりません。あるいは、エントリー アクターがこの情報を取得する方法を再考する必要があるかもしれません。

Object Account {
  def apply(region: String, accountId: String): Props = Props(new Account(region, accountId))
}

class Account(val region: String, val accountId: String) extends Actor with PersistentActor { ... }

ClusterSharding.startは、すべての Entry アクターを作成するために単一の Props インスタンスを取り込みます。

akka cluster-shardingから:

val counterRegion: ActorRef = ClusterSharding(system).start(
  typeName = "Counter",
  entryProps = Some(Props[Counter]),
  idExtractor = idExtractor,
  shardResolver = shardResolver)

次に、idExtractor の定義方法に基づいて、メッセージを受信する Entry アクターを解決します。shard のソース コードから、特定の Entry アクター インスタンスの名前として id を使用していることがわかります。

def getEntry(id: EntryId): ActorRef = {
val name = URLEncoder.encode(id, "utf-8")
context.child(name).getOrElse {
  log.debug("Starting entry [{}] in shard [{}]", id, shardId)

  val a = context.watch(context.actorOf(entryProps, name))
  idByRef = idByRef.updated(a, id)
  refById = refById.updated(id, a)
  state = state.copy(state.entries + id)
  a
}

}

代わりに、Entry アクターに、指定された名前でリージョンと accountId を把握させる必要があるようですが、値を直接取得するのではなく、文字列から解析するので、これは少しハッキリしています。これは私の最良の選択肢ですか?

4

1 に答える 1

12

私はあなたと非常によく似た状況にあります。正確な答えはありませんが、私がやったこと/試したこと/考えたことをあなたと読者と共有できます.

オプション 1) 前述のように、名前の付け方とパスの解析から ID、シャード、およびリージョン情報を抽出できます。利点は、a) 簡単に実行できることです。欠点は、a) Akka はアクター パスを UTF-8 としてエンコードするため、標準の URL 文字 (|| や w/e など) ではないセパレータとして何かを使用している場合は、最初に utf8 からデコードする必要があります。 . Akka の内部では utf8 がエンコード方法としてハードコードされていることに注意してください。関数のようにエンコード形式を抽出する方法はないため、明日 akka が変更された場合は、コードも調整する必要があります。b)あなたのシステムはもう準同型を保存していません(「ちょっとハッキーに感じる」とはどういう意味ですか)。これは、ある日、データに情報区切り文字列が意味のあるデータとして含まれ、システムが混乱する可能性があるというリスクを追加していることを意味します。

オプション 2) アクターが存在しない場合、シャーディングはアクターをスポーンします。そのため、コンストラクターのパラメーターを含む初期化されていないアクターに常に初期化メッセージを送信するコードを強制できます。シャードされたアクターの内部には、次のようなものがあります。

val par1: Option[param1Type] = None

def receive = {
    case init(par1value) => par1 = Some(par1value)
    case query(par1) => sender ! par1
}

また、リージョン アクセス アクターからは、常に最初にクエリ メッセージを送信し、次にリターンが None の場合は init メッセージを送信できます。これは、リージョン アクセス アクターが初期化されたアクターのリストを保持していないことを前提としています。その場合、init でスポーンしてから通常どおり使用できます。利点は、a) エレガントである b) 適切に「感じられる」ことです

欠点: a) 2 倍のメッセージが必要です (初期化されたアクターのリストを保持していない場合)。

オプション 3)このオプションはテスト済みであり、機能しません。人々が同じことをしようとして時間を無駄にしないように、ここに残しておきます。 これが機能するかどうかはわかりません。テストしていないのは、このシナリオを特別な制約のある本番環境で使用しており、派手なものは許可されていないためです ^_^ でも、お気軽に試してみて、午後またはコメントでお知らせください! 基本的に、あなたの地域を

val counterRegion: ActorRef = ClusterSharding(system).start(
  typeName = "Counter",
  entryProps = Some(Props[Counter]),
  idExtractor = idExtractor,
  shardResolver = shardResolver)

領域作成アクターで、次のようなことをするとどうなるでしょうか。

var providedPar1 = v1
def providePar1 = providedPar1

val counterRegion: ActorRef = ClusterSharding(system).start(
  typeName = "Counter",
  entryProps = Some(Props(classOf[Counter], providePar1),
  idExtractor = idExtractor,
  shardResolver = shardResolver)

そして、作成ごとに providedPar1 の値を変更しますか? これの欠点は、それが機能するオプションでは、アクターが作成されたことを 100% 確信するまで、providedPar1 の値を変更しないようにする必要があることです。 、競合状態!)

一般的には、オプション 2 の方が得策ですが、ほとんどのシナリオでは、オプション 1 によってもたらされるリスクは小さく、単純さ (およびパフォーマンス) の利点を考慮して適切に軽減できます。

この暴言がお役に立てば幸いです。どのように機能するかを3つ試してみたら教えてください!

于 2014-10-23T09:03:08.510 に答える