當前位置: 妍妍網 > 碼農

.NET分布式Orleans - 3 - Grain放置

2024-03-27碼農

在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上處理,減少了跨網路的通訊開銷。

    publicinterfaceIPlayerGrain : 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 地址return Task.FromResult(silos[index]); }}// 自訂 PlacementStrategy,用於指定使用自訂的 IPlacementDirector[Serializable]publicsealed classSameGamePlacementStrategy : PlacementStrategy{}[AttributeUsage(AttributeTargets. class, AllowMultiple = false)]publicsealed classSameGamePlacementStrategyAttribute : PlacementAttribute{publicSameGamePlacementStrategyAttribute() : base(new SameGamePlacementStrategy()) { }} classProgram{staticasync 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 => new SameGamePlacementDirector()); ; }); ; }) .ConfigureLogging(l => l.AddConsole()) .Build();await host.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();await host.StopAsync(); }}

    關註獲取技術分享