当Orleans激活一个Grain时,运行时会决定在哪个服务器(筒仓)上进行激活。这个过程叫做Grain放置。Orleans的放置机制是完全可配置的:开发者可以直接从一组开箱即用的放置策略中选择一种策略,如随机、本地优先、基于负载,也可以配置自定义逻辑。这就使得Grain的放置非常具有灵活性。例如,Grain可以被放置在距离它所操作的资源较近的服务器上,或者它需要进行通讯的其他Grain的服务器上。

自定义放置策略样例

创建一个类,让它实现IPlacementDirector接口,这个接口只需要实现一个方法。
在下面的示例中,我们假设你已经定义了一个名为GetSiloNumber的函数,当给定GUID的Grain要被创建的时候,该函数可以返回筒仓的编号。

  1. public class SamplePlacementStrategyFixedSiloDirector : IPlacementDirector
  2. {
  3. public Task<SiloAddress> OnAddActivation(PlacementStrategy strategy, PlacementTarget target, IPlacementContext context)
  4. {
  5. var silos = context.GetCompatibleSilos(target).OrderBy(s => s).ToArray();
  6. int silo = GetSiloNumber(target.GrainIdentity.PrimaryKey, silos.Length);
  7. return Task.FromResult(silos[silo]);
  8. }
  9. }

随后再定义两个类,用来帮助给Grain类配置指定的策略:

  1. [Serializable]
  2. public class SamplePlacementStrategy : PlacementStrategy
  3. {
  4. }
  5. [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
  6. public sealed class SamplePlacementStrategyAttribute : PlacementAttribute
  7. {
  8. public SamplePlacementStrategyAttribute() :
  9. base(new SamplePlacementStrategy())
  10. {
  11. }
  12. }

接下来,在Grain类上打好刚定义的对应的策略的特性标签,即可:

  1. [SamplePlacementStrategy]
  2. public class MyGrain : Grain, IMyGrain
  3. {
  4. ...
  5. }

最后,在构建SiloHost的时候,注册一下前面定义的策略:

  1. private static async Task<ISiloHost> StartSilo()
  2. {
  3. ISiloHostBuilder builder = new SiloHostBuilder()
  4. // normal configuration methods omitted for brevity
  5. .ConfigureServices(ConfigureServices);
  6. var host = builder.Build();
  7. await host.StartAsync();
  8. return host;
  9. }
  10. private static void ConfigureServices(IServiceCollection services)
  11. {
  12. services.AddSingletonNamedService<PlacementStrategy, SamplePlacementStrategy>(nameof(SamplePlacementStrategy));
  13. services.AddSingletonKeyedService<Type, IPlacementDirector, SamplePlacementStrategyFixedSiloDirector>(typeof(SamplePlacementStrategy));
  14. }

关于放置上下文的进一步的样例,见Orleans源代码中的PreferLocalPlacementDirector