简体   繁体   English

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

[英]Storing entity IDs in an Akka cluster using ClusterSharding

I have an akka.net cluster where I intend to use ClusterSharding to shard entities (actors) across the nodes in the cluster. 我有一个akka.net群集,我打算在其中使用ClusterSharding在群集中的各个节点之间分片实体(角色)。 Sitting above the cluster is a layer that will be a standard REST style API offering endpoints to create and retrieve the entities. 位于集群上方的是一层,它将是标准的REST风格的API,提供用于创建和检索实体的端点。 I would also like to be able to return, through this API, the IDs of all the entities currently in the cluster (as you would normally in a REST style API, for example via a GET on /api/entity) - these IDs would be a property of the entity or could be the full ID used by the ClusterSharding module when directing messages. 我还希望能够通过此API返回集群中当前所有实体的ID(就像您通常在REST风格的API中那样,例如通过/ api / entity上的GET)-这些ID将是实体的属性,或者是定向消息时ClusterSharding模块使用的完整ID。

Is there an easy way to retrieve all these IDs from the cluster? 是否有一种简单的方法可以从集群中检索所有这些ID? Or should I create a separate 'caching' actor that stores the IDs as and when the entities get created / recovered (in the case of a persistent actor) that the REST API layer can call directly? 还是应该创建一个单独的“缓存” actor来存储ID,并在创建/恢复实体时(对于持久性actor)将这些ID存储起来,REST API层可以直接调用这些ID? Or should the API layer query the cluster for the IDs each and every time it gets called (by broadcasting a message to all the entities and aggregating the responses)? 还是API层应该在每次调用集群时向集群查询ID(通过向所有实体广播消息并汇总响应)? This last one seems like it could be a bit wasteful, particularly in times when the list of entities is relatively static. 最后一个似乎有点浪费,尤其是在实体列表相对静态的时候。

Or am I missing something and need to design this differently? 还是我错过了一些东西,需要设计不同的东西?

Thanks for any help you can give. 谢谢你提供的所有帮助。

If you're interested only in entities that are currently alive, you can simply ask current shard region for its entity IDs: 如果您仅对当前处于活动状态的实体感兴趣,则可以简单地向当前碎片区域询问其实体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}");

This however will retrieve only information about entities living on a current cluster node, not everywhere. 但是,这将仅检索有关生活在当前群集节点上的实体的信息,而不是在任何地方。 You could however aggregate results if necessary: 但是,如果需要,您可以汇总结果:

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

Keep in mind, that that kind of request could be quite huge. 请记住,这种请求可能非常庞大。

While this one will allow you to retrieve informations about all EntityIDs on all nodes for a particular typeName, it still won't count inactive entities. 尽管此操作可以让您检索有关特定typeName的所有节点上所有EntityID的信息,但仍不计入非活动实体。

If you'd want to get IDs on all entities living on all nodes ever, you'd need to perform a query over a ReadJournal used by your sharding module. 如果要获取生活在所有节点上的所有实体的ID,则需要对分片模块使用的ReadJournal进行查询。 This requires two conditions to be met: 这需要满足两个条件:

  1. It works only if your cluster sharding extension is using persistent backend supporting Akka.Persistence.Query . 仅当您的群集分片扩展使用的是支持Akka.Persistence.Query的持久后端时,它才有效
  2. You need akka.cluster.sharding.remember-entities = on setting - it's turned off by default, and it will increase the cost of cluster sharding infrastructure once set on. 设置时需要akka.cluster.sharding.remember-entities = on -默认情况下处于关闭状态,一旦启用,它将增加集群分片基础架构的成本。

In case of SQL journals, it should look more or less like this: 如果是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);
}

Keep in mind that this kind of query may also be pretty expensive. 请记住,这种查询也可能非常昂贵。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM