粒紋放置

Orleans 可確保進行 Grain 呼叫時,叢集中某些伺服器上的記憶體中有該 Grain 的執行個體可用來處理要求。 如果叢集中目前未使用 Grain,Orleans 會挑選其中一部伺服器來啟用 Grain。 這稱為 Grain 放置。 放置也是平衡負載的其中一種方式:忙碌 Grain 的平均放置,也能協助平均整個叢集的工作負載。

可完全設定 Orleans 中的放置程序:開發人員可以從一組現成的放置原則中選擇,例如隨機、偏好本機和以負載為基礎,會是可以設定的自訂邏輯。 這讓您在決定 Grain 的建立位置上有完全的彈性。 例如,Grain 可以放在接近操作所需資源的伺服器上,或放在靠近其他 Grain 的位置以利通訊。 根據預設,Orleans 會挑選隨機相容的伺服器。

Orleans 使用的放置策略可以全域設定或根據各個 Grain 類別進行設定。

隨機放置

從叢集中的相容伺服器中隨機選取伺服器。 此放置策略是藉由將 RandomPlacementAttribute 新增至 Grain 來設定。

本機放置

如果本機伺服器相容,請選取本機伺服器,否則請選取隨機伺服器。 此放置策略是藉由將 PreferLocalPlacementAttribute 新增至 Grain 來設定。

雜湊型放置

將 Grain 識別碼雜湊為非負整數,並以相容的伺服器數目來計算模數。 從依伺服器位址排序的相容伺服器清單中選取對應的伺服器。 請注意,這不保證可在叢集成員資格變更時保持穩定。 具體而言,新增、移除或重新啟動伺服器可能會改變針對指定 Grain 識別碼選取的伺服器。由於使用此策略放置的 Grain 會登錄在 Grain 目錄中,因此隨著成員資格變更的此放置決策變更通常不會有明顯的影響。

此放置策略是藉由將 HashBasedPlacementAttribute 新增至 Grain 來設定。

以啟用計數為基礎的放置

此放置策略會根據最近的忙碌 Grain 數目,將新的 Grain 啟用放在負載最低的伺服器上。 此策略包含一種機制,其中所有伺服器都會定期將其啟用總數發佈至所有其他伺服器。 接著,放置控制器會藉由檢查最近回報的啟用計數,並根據放置控制器在目前伺服器上所做的最近啟用計數,來預測目前啟用計數,進而選取預測會有最少啟用的伺服器。 控制器會在進行此預測時隨機選取數部伺服器,以試圖避免多個不同伺服器多載同一部伺服器。 預設會隨機選取兩部伺服器,但此值可透過 ActivationCountBasedPlacementOptions 設定。

此演算法是以 Michael David Mitzenmacher 的<隨機化負載平衡中兩個選項的力量>為基礎,也會在 Nginx 中用於分散式負載平衡,如<NGINX 和「兩個選項的力量」負載平衡演算法>一文中所述。

此放置策略是藉由將 ActivationCountBasedPlacementAttribute 新增至 Grain 來設定。

無狀態背景工作角色放置

無狀態背景工作角色放置是無狀態背景工作角色 Grain 所使用的特殊放置策略。 此放置的運作方式幾乎與 PreferLocalPlacement 相同,不同之處在於每部伺服器可以有多個相同 Grain 的啟用,而且不需要在 Grain 目錄中登錄 Grain。

此放置策略是藉由將 StatelessWorkerAttribute 新增至 Grain 來設定。

以定址接收器角色為基礎的放置

這是具決定性的放置策略,可將 Grain 放在具有特定角色的定址接收器上。 此放置策略是藉由將 SiloRoleBasedPlacementAttribute 新增至 Grain 來設定。

選擇放置策略

選擇適當的 Grain 放置策略 (除了 Orleans 所提供的預設值外),需要監視和開發人員評估。 放置策略的選擇應該以應用程式的大小和複雜度、工作負載特性和部署環境為基礎。

隨機放置依賴大數法則,因此,當無法預期分散到大量 Grain (10,000 個以上) 的負載時,這通常會是很好的預設值。

以啟用計數為基礎的放置也有隨機元素 (依賴「兩個選項的力量」原則),這是分散式負載平衡的常用演算法,並且用於熱門的負載平衡器。 定址接收器經常將執行階段統計資料發佈至叢集中的其他定址接收器,包括:

  • 可用的記憶體、實體記憶體總計和記憶體使用量。
  • CPU 使用量。
  • 啟用計數總計和最近作用中啟用計數。
    • 過去幾秒內作用中的啟用滑動視窗,有時稱為啟用工作集。

在這些統計資料中,目前只會使用啟用計數來判斷指定定址接收器上的負載。

最後,您應該試驗不同的策略並監視效能計量,以判斷最適合的策略。 藉由選取正確的 Grain 放置策略,您可以將 Orleans 應用程式的效能、可擴縮性和成本效益最佳化。

設定預設放置策略

除非覆寫預設值,否則 Orleans 會使用隨機放置。 在設定期間註冊 PlacementStrategy 實作,即可覆寫預設放置策略:

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

設定 Grain 的放置策略

Grain 類型的放置策略是藉由在 Grain 類別上新增適當屬性來設定。 相關屬性會在 [放置策略] 區段中指定。

自訂放置策略範例

首先定義實作 IPlacementDirector 介面的類別,而這需要單一方法。 在此範例中,我們假設您已定義 GetSiloNumber 函式,而這會針對即將建立的 Grain Guid 傳回定址接收器編號。

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 sealed 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()
{
    var builder = new HostBuilder(c =>
    {
        // normal configuration methods omitted for brevity
        c.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