群集感知路由器:
val router = system.actorOf(ClusterRouterPool(
RoundRobinPool(0),
ClusterRouterPoolSettings(
totalInstances = 20,
maxInstancesPerNode = 1,
allowLocalRoutees = false,
useRole = None
)
).props(Props[Worker]), name = "router")
在这里,我们可以向router
发送消息,消息将发送给一系列远程特工演员。
群集分片(不考虑持久性)
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
发送消息,消息将发送给一系列分片演员(a.k.a.实体)。
所以,我的问题是: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?
答案 0 :(得分:2)
池路由器就是当你只想将一些工作发送到任何节点并进行一些处理时,按顺序发送的两条消息可能不会在同一个actor中结束进行处理。
群集分片是指在某种类型的每个actor上都有一个唯一ID,并且你有太多它们不适合一个节点,但是你希望每个带有该id的消息总是在actor的那个节点中结束ID。例如,将User
建模为实体,您希望有关该用户的所有命令都以用户结束,但是如果群集拓扑发生更改(删除或添加节点)并且您希望合理地使用它们,则希望移动actor在现有节点之间保持平衡。
答案 1 :(得分:0)
向johanandren致谢,并将链接的文章作为以下答案的依据:
router
和sharding
均分发工作。如果除了负载平衡之外,接收方参与者还必须可靠地管理与Sharding
直接相关的状态,则需要entity identifier
。
回顾一下,entity identifier
是一个密钥,从发送的邮件派生而来,它确定邮件在群集中的接收者。
首先,您可以使用一致的哈希路由器来管理与跨不同节点的identifier
关联的状态吗? Consistent Hash
路由器将始终将具有相等的identifier
的消息发送到同一目标参与者。答案是:否,如下所述。
当集群中的节点出现故障或出现故障时,基于散列的方法将停止工作,因为这会更改某些标识符的关联参与者。如果某个节点发生故障,则与之关联的消息现在将发送到网络中的其他参与者,但是不会通知该参与者当前正在替换的参与者的先前状态。同样,如果出现新节点,它将处理先前与其他参与者关联的消息(标识符),并且新节点或旧节点都不会被告知。
另一方面,通过分片,创建的actor知道他们管理的entity identifier
。 Sharding
将确保集群中只有一个参与者来管理实体。如果其父节点发生故障,它将在另一个节点上重新创建分片actor。因此,使用persistence
时,当节点数更改时,它们将在节点之间保留其(持久)状态。如果借助Sharding在不同的节点上重新创建actor,您也不必担心并发问题。此外,如果遇到带有新的entity identifier
的消息,而该参与者还不存在该参与者,则会创建一个新的参与者。
一致的哈希路由器可能仍可用于缓存,因为通常具有相同密钥的消息会发往同一参与者。要管理在集群中仅存在一次的有状态实体,需要Sharding
。
使用路由器进行负载平衡,使用Sharding
以分布式方式管理有状态实体。