使用ClusterSharding在Akka集群中存储实体ID

时间:2017-09-06 11:01:01

标签: c# akka akka.net

我有一个akka.net集群,我打算使用ClusterSharding在集群中的节点之间对实体(actor)进行分片。位于集群上方的是一个层,它将是一个标准的REST样式API,提供创建和检索实体的端点。我还希望能够通过此API返回当前群集中所有实体的ID(正如您通常在REST样式API中,例如通过/ api / entity上的GET) - 这些ID将是实体的属性,或者可以是ClusterSharding模块在定向消息时使用的完整ID。

有没有一种简单的方法可以从群集中检索所有这些ID?或者我应该创建一个单独的缓存'在创建/恢复实体时(在持久化actor的情况下)REST API层可以直接调用的存储ID的actor?或者API层是否应该在每次调用时向集群查询ID(通过向所有实体广播消息并聚合响应)?最后一个看起来可能有点浪费,特别是在实体列表相对静止的时候。

或者我错过了什么,需要以不同的方式进行设计?

感谢您提供任何帮助。

1 个答案:

答案 0 :(得分:0)

如果您只对当前存活的实体感兴趣,可以直接询问当前分片区域的实体ID:

var region = ClusterSharding.Get(system).ShardRegion(typeName);
var state = await region.Ask<CurrentShardRegionState>(GetShardRegionState.Instance);
foreach (var shard in state.Shards) 
    foreach(var entityId in shard.EntityIds)
        Console.WriteLine($"{typeName}/{shard.ShardId}/{entityId}");

然而,这将仅检索有关生活在当前群集节点上的实体的信息,而不是任何地方。但是,如有必要,您可以汇总结果:

var cluster = Cluster.Get(system);
var region = ClusterSharding.Get(system).ShardRegion(typeName);
var members = cluster.State.Members;
var regions = members
    .Select(m => region.Path.ToStringWithAddress(m.Address))
    .Select(system.ActorSelection);

// at this point regions variable is a collection of ActorSelections poiting
// to regions on all known nodes. You can use Ask pattern on them directly

请记住,这种要求可能非常大。

虽然这个允许您检索有关特定typeName的所有节点上的所有EntityID的信息,但它仍然不会计算非活动实体。

如果您希望获取所有节点上所有实体的ID,则需要对分片模块使用的ReadJournal执行查询。这需要满足两个条件:

  1. 仅当您的群集分片扩展使用支持 Akka.Persistence.Query 的持久后端时才有效。
  2. 您需要akka.cluster.sharding.remember-entities = on设置 - 默认情况下已关闭,一旦设置,它将增加群集分片基础架构的成本。
  3. 对于SQL期刊,它应该或多或少看起来像这样:

    var queries = PersistenceQuery.Get(actorSystem)
        .ReadJournalFor<SqlReadJournal>("path-to-sharding-journal");
    
    var shardPrefix = "/sharding/" + typeName + "Shard/"
    Source<string, NotUsed> entitySource = queries
        .AllPersistenceIds() 
        .Where(pid => pid.StartsWith(shardPrefix)) // get all shard IDs ever known
        .ConcatMany(shardId => queries.CurrentEventsByPersistenceId(shardId)) // get stream of persisted events for each shard (you may need to stretch the query limit here)
        .Collect(env => env.Event as Shard.EntityStarted) // filter out EntityStarted events
        .Select(e => e.EntityId); // extract entity ID
    
    using (var mat = system.Materializer())
    {
        // materialize source into a list
        var entityIds = await entitySource
            .RunAggregate(ImmutableList<string>.Emtpy, (acc, id) => acc.Add(id), mat);
    }
    

    请记住,这种查询也可能非常昂贵。