集群感知路由器和集群分片的不同用例?

Different use case for akka cluster aware router & akka cluster sharding?

  1. 集群感知路由器:

    val router = system.actorOf(ClusterRouterPool(
      RoundRobinPool(0),
      ClusterRouterPoolSettings(
        totalInstances = 20,
        maxInstancesPerNode = 1,
        allowLocalRoutees = false,
        useRole = None
      )
    ).props(Props[Worker]), name = "router")
    

    在这里,我们可以发送消息给router,消息会发送给一系列远程routee actor。

  2. 集群分片(不考虑持久化)

    class NewShoppers extends Actor {
      ClusterSharding(context.system).start(
        "shardshoppers",
        Props(new Shopper),
        ClusterShardingSettings(context.system),
        Shopper.extractEntityId,
        Shopper.extractShardId
      )
    
      def proxy = {
        ClusterSharding(context.system).shardRegion("shardshoppers")
      }
    
      override def receive: Receive = {
        case msg => proxy forward msg
      }
    }
    

    在这里,我们可以发送消息到proxy,消息将发送到一系列分片actor(a.k.a.entities)。

所以,我的问题是:it seems both 2 methods can make the tasks distribute to a lot of actors. What's the design choice of above two? Which situation need which choice?

当您只想将一些工作发送到任何节点并进行一些处理时,池路由器将是这样,按顺序发送的两条消息可能不会在同一个 actor 中结束以进行处理。

集群分片适用于当您在某种类型的每个 actor 上都有一个唯一的 id,并且它们太多而无法放入一个节点,但您希望具有该 id 的每条消息总是在 actor 中结束对于那个ID。例如,将 User 建模为一个实体,您希望所有关于该用户的命令都以该用户结束,但您希望在集群拓扑发生变化(删除或添加节点)时移动参与者,并且您希望它们合理在现有节点之间保持平衡。

感谢 johanandren 和链接文章作为以下答案的基础:

routersharding 都分配工作。 Sharding 是必需的,如果除了负载平衡之外,接收者参与者还必须可靠地管理与 entity identifier 直接关联的状态。

回顾一下,entity identifier 是一个密钥,从正在发送的消息中派生,确定消息在集群中的接收者角色。

首先,您能否使用一致的散列路由器管理与跨不同节点的 identifier 关联的状态? Consistent Hash 路由器将始终向同一目标参与者发送具有相等 identifier 的消息。答案是:没有,如下所述。

当集群中的节点关闭或启动时,hash-based 方法停止工作,因为这会更改某些标识符的关联参与者。如果一个节点出现故障,与其关联的消息现在将发送到网络中的另一个参与者,但该参与者不会被告知它现在正在替换的参与者的先前状态。同样,如果出现新节点,它将处理先前与不同参与者相关联的消息(标识符),并且新节点或旧节点都不会被告知这一点。

另一方面,通过分片,创建的参与者知道他们管理的entity identifierSharding 将确保只有一个参与者管理集群中的实体。如果他们的父节点出现故障,它将 re-create 在不同的节点上分片演员。因此,当节点数量发生变化时,使用 persistence 它们将跨节点保留其(持久)状态。如果一个 actor re-created 在不同的节点上,你也不必担心并发问题,这要归功于分片。此外,如果遇到带有新 entity identifier 的消息,而该消息的参与者尚不存在,则会创建一个新的参与者。

一致的散列路由器可能仍可用于缓存,因为具有相同密钥的消息通常确实会发送给同一个参与者。要管理在集群中仅存在一次的有状态实体,需要 Sharding

使用路由器进行负载平衡,使用Sharding以分布式方式管理有状态实体。