当Orleans激活一个Grain时,运行时会决定在哪个服务器(筒仓)上进行激活。这个过程叫做Grain放置。Orleans的放置机制是完全可配置的:开发者可以直接从一组开箱即用的放置策略中选择一种策略,如随机、本地优先、基于负载,也可以配置自定义逻辑。这就使得Grain的放置非常具有灵活性。例如,Grain可以被放置在距离它所操作的资源较近的服务器上,或者它需要进行通讯的其他Grain的服务器上。
自定义放置策略样例
创建一个类,让它实现IPlacementDirector
接口,这个接口只需要实现一个方法。
在下面的示例中,我们假设你已经定义了一个名为GetSiloNumber
的函数,当给定GUID的Grain要被创建的时候,该函数可以返回筒仓的编号。
public class SamplePlacementStrategyFixedSiloDirector : IPlacementDirector
{
public Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)
{
var silos = context.GetCompatibleSilos(target).OrderBy(s => s).ToArray();
int silo = GetSiloNumber(target.GrainIdentity.PrimaryKey, silos.Length);
return Task.FromResult(silos[silo]);
}
}
随后再定义两个类,用来帮助给Grain类配置指定的策略:
[Serializable]
public class SamplePlacementStrategy : PlacementStrategy
{
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class SamplePlacementStrategyAttribute : PlacementAttribute
{
public SamplePlacementStrategyAttribute() :
base(new SamplePlacementStrategy())
{
}
}
接下来,在Grain类上打好刚定义的对应的策略的特性标签,即可:
[SamplePlacementStrategy]
public class MyGrain : Grain, IMyGrain
{
...
}
最后,在构建SiloHost的时候,注册一下前面定义的策略:
private static async Task<ISiloHost> StartSilo()
{
ISiloHostBuilder builder = new SiloHostBuilder()
// normal configuration methods omitted for brevity
.ConfigureServices(ConfigureServices);
var host = builder.Build();
await host.StartAsync();
return host;
}
private static void ConfigureServices(IServiceCollection services)
{
services.AddSingletonNamedService<PlacementStrategy, SamplePlacementStrategy>(nameof(SamplePlacementStrategy));
services.AddSingletonKeyedService<Type, IPlacementDirector, SamplePlacementStrategyFixedSiloDirector>(typeof(SamplePlacementStrategy));
}
关于放置上下文的进一步的样例,见Orleans源代码中的PreferLocalPlacementDirector
。