首页 文章

Akka cluster-sharding:Entry actor可以拥有动态道具

提问于
浏览
10

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 .

akka cluster-sharding

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我会用字符串解析它而不是直接获取值 . 这是我最好的选择吗?

1 回答

  • 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消息(如果你没有维护一个初始化的actor列表)

    选项3) THIS OPTION HAS BEEN TESTED AND DOESN'T WORK. I'll just leave it here for people to avoid wasting time trying the same. 我不知道这是否有效,我没有't tested because I'米在 生产环境 中使用这种情况有特殊限制,不允许使用花哨的东西^ _ ^但是请随意尝试,请让我知道下午或评论!基本上,你开始你的地区

    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它是如何工作的,请告诉我!

相关问题