我有一个akka.net集群,我打算使用ClusterSharding在集群中的节点之间对实体(actor)进行分片。位于集群上方的是一个层,它将是一个标准的REST样式API,提供创建和检索实体的端点。我还希望能够通过此API返回当前群集中所有实体的ID(正如您通常在REST样式API中,例如通过/ api / entity上的GET) - 这些ID将是实体的属性,或者可以是ClusterSharding模块在定向消息时使用的完整ID。
有没有一种简单的方法可以从群集中检索所有这些ID?或者我应该创建一个单独的缓存'在创建/恢复实体时(在持久化actor的情况下)REST API层可以直接调用的存储ID的actor?或者API层是否应该在每次调用时向集群查询ID(通过向所有实体广播消息并聚合响应)?最后一个看起来可能有点浪费,特别是在实体列表相对静止的时候。
或者我错过了什么,需要以不同的方式进行设计?
感谢您提供任何帮助。
答案 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执行查询。这需要满足两个条件:
akka.cluster.sharding.remember-entities = on
设置 - 默认情况下已关闭,一旦设置,它将增加群集分片基础架构的成本。对于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);
}
请记住,这种查询也可能非常昂贵。