Akka Cluster-Sharding看起来与用例很匹配我必须在Akka节点上创建有状态持久性actor的单个实例。
我不清楚是否有可能有一个Entry actor类型需要参数来构造它。或者我可能需要重新考虑Entry actor如何获取此信息。
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
接受一个Props实例来创建所有Entry actor。
val counterRegion: ActorRef = ClusterSharding(system).start(
typeName = "Counter",
entryProps = Some(Props[Counter]),
idExtractor = idExtractor,
shardResolver = shardResolver)
然后它解析了根据你如何定义idExtractor接收消息的Entry actor。从分片的源代码可以看出它使用id作为给定Entry actor实例的名称:
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 actor通过它给出的名称来确定它的区域和accountId,虽然现在我觉得有点hacky我会用字符串解析它而不是直接获取它价值。这是我最好的选择吗?
答案 0 :(得分:11)
我和你的情况非常相似。我没有确切的答案,但我可以与你和读者分享我做过/尝试/想过的事情。
选项1)正如您所提到的,您可以从命名内容和解析路径的方式中提取id,分片和区域信息。好处是 a)这很容易做到。 缺点是 a)Akka将actor路径编码为UTF-8,因此如果你使用任何东西作为不是标准url字符的分隔符(例如||或w / e),你需要先从utf8解码它。请注意,在Akka utf8内部是硬编码的编码方法,没有办法像函数中那样提取编码格式,所以如果明天akka改变你也必须调整你的代码。 b)你的系统不再保留同态(你的意思是“感觉有点像hacky”)。这意味着您要添加的风险是,您的数据有一天可能会将您的信息分隔符字符串包含为有意义的数据,并且您的系统可能会陷入困境。
选项2)如果不存在,则Sharding将生成您的actor。因此,您可以强制您的代码始终向非初始化的actor发送init消息,其中包含构造函数参数。你的分片演员会有类似的东西:
val par1: Option[param1Type] = None
def receive = {
case init(par1value) => par1 = Some(par1value)
case query(par1) => sender ! par1
}
从您所在的区域访问actor,您始终可以先发送查询消息,然后在返回为None时发送init消息。这假设您的区域访问actor没有保留初始化actor的列表,在这种情况下,您可以使用init生成然后正常使用它们。 好处是 a)很优雅 b)它“感觉”正确
下行:a)它需要2x消息(如果你没有维护初始化的演员列表)
选项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的值?这样做的缺点是,在它可以使用的选项中,你需要避免更改providedPar1的值,直到你100%确定已经创建了actor,否则你可能会冒险访问新的错误值(yay) ,竞争条件!)
一般情况下,使用选项2 imho会更好,但在大多数情况下,1引入的风险很小,并且考虑到简单(和性能)优势,您可以适当地减轻它们。
希望这个咆哮有所帮助,如果你尝试3它是如何工作的,请告诉我!