群集一致的哈希池为同一映射生成新的routee

时间:2017-05-04 13:33:39

标签: akka.net consistent-hashing akka.net-cluster

我有一个包含2个命令行项目的解决方案,可以创建一个带有种子和客户端进程的akka​​.net集群。种子启动集群然后实例化一致哈希集群路由器,该路由器对任何实现我的接口的消息执行哈希映射" IHasRouting"。因此,任何IHasRouting消息(来自种子或客户端)都应该最终在该路由器的种子上以获取该消息的散列。

项目开始正常,群集形成没有错误。种子和客户端都实例化路由器。来自种子和客户端的所有消息都具有相同的" VolumeId"所以他们应该在种子上走同一条路。 但来自客户端节点的消息会在种子上为这些消息产生新的保证!

我对一致哈希集群路由器的理解是:

  • IActorRef表示它应该在该节点中的actor打算向路由器发送消息的每个节点上退出。
  • 路由器的实现在每个节点上应该相同,并且具有相同的actor名称。
  • 路由器的所有消息都应该实现IConsistentHash,或者路由器实例应该有" WithHashMapping()"
  • 具有相同哈希值的所有邮件将仅到达一个routee,并且它将始终是相同的routee
  • 可以使用多个哈希

我相信我理解一致哈希集群路由器应该如何运行,并且大量的DEV似乎正确使用路由器类型,因此我的实现必定是错误的...请帮忙!如果有帮助,我可以提供完整的解决方案。

创建路由器的代码:

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");

我有一个"公司"消息到路由器所需的类。此测试的所有VolumeId都相同。

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;
    }
}

最后是在路由器上为每个routee实例化的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);
    }
}

感谢任何指导。

2 个答案:

答案 0 :(得分:0)

当您正在调用ul.dropdown-menu li:hover { background-color:red!important; } 时,您实际上正在当前群集节点上创建新的actor实例。在池路由器的情况下,创建新路由器还将创建新的routee actor池,可以通过其他节点分派。这也意味着,就是你要两次调用ul.dropdown-menu li a:hover { background-color:red!important; } (一个在客户端节点上,一个在种子节点上),结果你将收到两个独立的演员池。

  1. 解决此问题的最简单方法是,只需将路由器池实例化一次 - 让它在集群节点之间分配路由池 - 并通过节点转发所有请求,该节点充当集群的入口点。您可以将其他节点配置为故障转移,以重新生成入口节点中的任务失败。
  2. 要做的另一件事是使用Distributed Pub/Subcluster sharding,具体取决于您使用群集邮件路由的目的。

答案 1 :(得分:0)

经过调查,我同意我对clustered-consistent-hash-router的理解是错误的。我现在明白我需要将代表路由器的IActorRef传递给集群的其余部分。这可以通过ClusterSinglton或(可能)某种类型的分布式pub子机制来完成。机制需要处理节点或Actor变为“丢失”的情况,实例化新的Actor(具有新路由)并且将新的Actor传递给具有先前引用的集群中的所有那些。

我正在研究群集分片方法,并将针对我采用该方法遇到的技术问题发布另一个问题。