2017-05-04 89 views
2

我有一个解决方案,包含2个命令行项目,创建一个带有种子和客户端进程的akka​​.net集群。种子启动群集,然后实例化一个一致的散列簇路由器,该路由器对实现我的接口“IHasRouting”的任何消息执行散列映射。因此,任何IHasRouting消息(来自种子或客户端)应最终在该消息散列的路由器上种子。集群一致的散列池为相同的映射生成新的routee

项目正常启动并且群集表单没有错误。种子和客户端实例化路由器。来自种子和客户端的所有消息都具有相同的“VolumeId”,因此它们应该在种子中转到相同的路由。 但是来自客户端节点的消息为这些消息在种子上产生了新的routee!

我一致的散列集群路由器的理解是:

  • 的IActorRef represting它应该退出,其中的演员在该节点打算将消息发送到路由器的每个节点上。
  • 路由器的实现应该在每个节点上相同,并且具有相同的actor名称。
  • 到路由器的所有信息应实现IConsistentHash或路由器的情况下应该有一个“WithHashMapping()”
  • 具有相同散列所有消息都将只在一个routee到达,这将始终是相同的routee
  • 一routee可能需要不止一个哈希

我相信我的理解一致的散列集群路由器应该如何表现和大量的开发者并似乎被正确使用路由器的类型,所以我的实现必须是错的.. 。 请帮忙!如果有帮助,我可以提供完整的解决方案。

创建路由器代码:

system.ActorOf(
    new ClusterRouterPool(
     local: new ConsistentHashingPool(nrOfInstances: 1) 
      .WithHashMapping(m => (m as IHasRouting)?.Company?.VolumeId ?? throw new Exception("no routing!")), 
       settings: new ClusterRouterPoolSettings(
        100, 
        100, 
        allowLocalRoutees: allowLocalRoutees, //true if the node role is a Seed 
        useRole: "Seed")) 
        .Props(Props.Create(() => new CompanyDeliveryActor())), "company-router"); 

我有一个消息需要的路由器一个“公司”类。所有VolumeIds对于此测试都是相同的。

public class Company 
{ 
    public readonly Guid CompanyId; 
    public readonly Guid VolumeId; 
    public readonly string CompanyName; 
    public Company(Guid companyId, Guid volumeId, string companyName) 
    { 
     this.CompanyId = companyId; 
     this.VolumeId = volumeId; 
     this.CompanyName = companyName; 
    } 
} 

所使用的路由器映射的IHasRouting接口:

public interface IHasRouting 
{ 
    Company Company { get; } 
} 

可被发送到路由器的一个例子的消息类别:

public class GetTripsMessage : IHasRouting 
{ 
    public Company Company { get; private set; } 
    public GetTripsMessage(Company company) 
    { 
     this.Company = company; 
    } 
} 

终于CompanyDeliverActor这是为路由器上的每个路由器实例化:

public class CompanyDeliveryActor : ReceiveActor 
{ 
    private readonly Dictionary<Guid, IActorRef> companyManagers = new Dictionary<Guid, IActorRef>(); 
    private readonly Guid instanceid = Guid.NewGuid(); 

    public CompanyDeliveryActor() 
    { 
     this.Receive<GetTripsMessage>(m => this.RouteCompanyMessage(m, m.Company)); 
     this.Receive<SetTripsMessage>(m => this.RouteCompanyMessage(m, m.Company)); 
    } 

    private void RouteCompanyMessage(object m, Company company) 
    { 
     //placing a watch here shows that this.instanceid is different for messages from the client. 

     if (!this.companyManagers.TryGetValue(company.CompanyId, out var manager)) 
     { 
      manager = Context.ActorOf(Props.Create(() => new CompanyManagerActor())); 
      this.companyManagers[company.CompanyId] = manager;     
     } 

     manager.Tell(m, Context.Sender); 
    } 
} 

感谢您的任何指导。

回答

0

当你打电话给ActorOf时,你实际上是在当前群集节点上创建一个新的actor实例。在池路由器的情况下,创建新路由器也会创建一个新的路由器角色池,这可能会通过其他节点分派。这也意味着,你要调用ActorOf两次(一个在客户端节点上,一个在种子节点上),结果你会得到两个独立的演员池。

  1. 来解决,这是简单地具有路由器池实例化一次最简单的方法 - 让它routees的调度池在集群节点 - 通过节点,作为切入点,以集群转发所有的请求。您可以将其他节点配置为故障转移,以重新录制入口节点中的任务失败。
  2. 另一件事要做的就是为使用Distributed Pub/Subcluster sharding这取决于你在使用群集消息路由上。
+0

谢谢 - 我的理解是错误的。我不明白只有一个IActorRef应该存在,并且它应该传递给所有其他节点(可能在其他节点上),以便将消息发送到集群一致性哈希池路由器进行分发。 –

+0

这就是为什么你有其他更高级的选项。我不知道为什么你的确切用例,但我知道人们通常会错误地选择一致的哈希路由器,而他们实际上需要的是集群分片(请阅读我在答案中链接的博客文章)。 – Horusiath

0

调查后,我同意我的群集一致哈希路由器的理解是错误的。我现在明白,我需要将表示路由器的IActorRef与集群的其余部分进行通信。这可以通过ClusterSinglton或(可能)某种类型的分布式pub子机制来完成。一个机制需要处理,其中节点或演员成为“迷失”,一个新的演员(新routees)被实例化的情况和新的演员传达给所有集群中的那些有先前的参考。

我调查群集分片的方式,将发布在问候的技术困难,我这种做法有另外一个问题。

+0

新问题是[簇分片的客户端 - 不连接 - 与主机(http://stackoverflow.com/questions/43829788/cluster-sharding-client-not-connecting-with-host) –

相关问题