在Orleans 7中,Grain放置是指确定将Grain对象放置在Orleans集群中的哪些物理节点上的过程。

Grain是Orleans中的基本单位,代表应用程序中的逻辑单元或实体。Grain放置策略是一种机制,用于根据不同的因素,将Grain对象放置在合适的节点上,以实现负载均衡、最小化网络延迟和提高容错性。

Grain放置的概念

Grain放置是指将Grain对象放置在Orleans集群中的物理节点上的过程。每个Grain对象都有一个唯一的标识符,Orleans根据Grain对象的标识符以及放置策略来决定将Grain对象放置在哪个节点上。

Grain放置的依据

Orleans 7中Grain放置的依据主要包括:

  • 负载均衡:确保集群中的每个节点负载尽可能均衡,避免某些节点负载过重。
  • 网络拓扑:考虑物理网络拓扑结构,将Grain对象放置在合适的物理节点上,以减少通信延迟。
  • 容错性:确保Grain对象在集群中的高可用性和容错性,避免单点故障。

Grain放置策略

Orleans 7中常见的Grain放置策略包括:

  • RandomPlacement:随机选择一个可用节点来放置Grain对象。这也是默认的策略。
  • ActivationCountBasedPlacement:根据节点上已激活的Grain对象数量选择当前负载最轻的节点来放置Grain对象,以实现负载均衡。
  • PreferLocalPlacement:优先将Grain对象放置在发起调用的本地节点上,以减少跨节点通信的延迟。
  • CustomPlacement:允许用户根据特定需求自定义Grain放置策略。

配置默认放置策略

Orleans 默认将使用随机放置。 可以通过在配置期间注册实现 PlacementStrategy 来重写默认放置策略:

siloBuilder.ConfigureServices(services =>services.AddSingleton<PlacementStrategy, MyPlacementStrategy>());

自定义标记属性以节省网络开销

如果希望将不同Client的Grain对象放置在同一个Silo上,以节省网络开销,可以使用自定义标记属性和自定义放置策略来实现。

下面的代码是个例子,在一个游戏中,可以为每个玩家定义一个唯一的标记属性,然后使用自定义放置策略确保具有相同标记属性的Grain对象被放置在同一个Silo上。

这样,同一游戏中不同玩家的Grain对象就可以在同一个Silo上处理,减少了跨网络的通信开销。

public interfaceIPlayerGrain : IGrainWithStringKey
{
Task
<string>GetPlayerInfo();
}

[SameGamePlacementStrategy]
public classPlayerGrain : Grain, IPlayerGrain
{
public Task<string>GetPlayerInfo()
{
return Task.FromResult($"Player ID: {this.GetPrimaryKeyString()}");
}
}
//自定义 IPlacementDirector,用于指定将相同游戏中的不同玩家放置在同一个 Silo 上 public classSameGamePlacementDirector : IPlacementDirector
{
public Task<SiloAddress>OnAddActivation(
PlacementStrategy strategy,
PlacementTarget target,
IPlacementContext context)
{
//获取游戏 ID,这里简单假设游戏 ID 是整数类型 int gameId = int.Parse(target.GrainIdentity.Key.ToString().Split('#')[0]);//将游戏 ID 映射到 Silo 的哈希值 int hashCode =gameId.GetHashCode();//获取 Silo 集群中的 Silo 列表 var silos =context.GetCompatibleSilos(target).ToArray();//计算 Silo 的索引 int index = Math.Abs(hashCode %silos.Length);//返回被选中的 Silo 地址 returnTask.FromResult(silos[index]);
}
}
//自定义 PlacementStrategy,用于指定使用自定义的 IPlacementDirector [Serializable]public sealed classSameGamePlacementStrategy : PlacementStrategy
{

}

[AttributeUsage(AttributeTargets.Class, AllowMultiple
= false)]public sealed classSameGamePlacementStrategyAttribute : PlacementAttribute
{
public SameGamePlacementStrategyAttribute() : base(newSameGamePlacementStrategy())
{
}
}
classProgram
{
static async Task Main(string[] args)
{
var host =Host.CreateDefaultBuilder()
.ConfigureServices((context, services)
=>{
services.AddOrleans(builder
=>{
builder
.UseLocalhostClustering()
.Configure
<ClusterOptions>(options =>{
options.ClusterId
= "dev";
options.ServiceId
= "OrleansExample";
})
.AddMemoryGrainStorage(
"playerGrainStorage")
.AddPlacementDirector
<SameGamePlacementStrategy>(sp => newSameGamePlacementDirector()); ;
}); ;

})
.ConfigureLogging(l
=>l.AddConsole())
.Build();
awaithost.StartAsync();var client = host.Services.GetRequiredService<IClusterClient>();var gameId = "123";var pId = gameId + "#" + Guid.NewGuid().ToString("N");var a = await client.GetGrain<IPlayerGrain>(pId).GetPlayerInfo();

Console.ReadKey();
awaithost.StopAsync();
}
}

标签: none

添加新评论