Dela via


Kornplacering

Orleans ser till att när ett grainanrop görs finns det en instans av det anropet som är tillgängligt i minnet på någon server i klustret för att hantera begäran. Om kornet för närvarande inte är aktivt i klustret väljer Orleans en av servrarna för att aktivera kornet på. Detta kallas kornplacering. Placering är också ett sätt att balansera belastningen: även placeringen av upptagna korn hjälper till att jämna ut arbetsbelastningen i klustret.

Placeringsprocessen i Orleans är helt konfigurerbar: utvecklare kan välja mellan en uppsättning färdiga placeringsprinciper, till exempel slumpmässig, föredrar lokal och belastningsbaserad eller anpassad logik kan konfigureras. Detta ger fullständig flexibilitet när du bestämmer var korn skapas. Till exempel kan korn placeras på en server nära resurser som de behöver arbeta på eller nära andra korn som de kommunicerar med. Som standard väljer Orleans en slumpmässigt kompatibel server.

Placeringsstrategin som Orleans använder kan konfigureras globalt eller per kornklass.

Slumpmässig placering

En server väljs slumpmässigt från de kompatibla servrarna i klustret. Den här placeringsstrategin konfigureras genom att lägga till RandomPlacementAttribute i ett korn.

Lokal placering

Om den lokala servern är kompatibel väljer du den lokala servern, annars väljer du en slumpmässig server. Den här placeringsstrategin konfigureras genom att lägga till PreferLocalPlacementAttribute i ett korn.

Hash-baserad placering

Hash korn-ID till ett icke-negativt heltal och modulera det med antalet kompatibla servrar. Välj motsvarande server i listan över kompatibla servrar som sorteras efter serveradress. Observera att detta inte garanteras vara stabilt när klustermedlemskapet ändras. Mer specifikt kan tillägg, borttagning eller omstart av servrar ändra vilken server som väljs för ett visst grain-id. Eftersom grains som placeras med den här strategin registreras i grainkatalogen, har sådana ändringar i placeringsbeslutet i samband med medlemskapsändringar vanligtvis ingen märkbar effekt.

Den här placeringsstrategin konfigureras genom att lägga till HashBasedPlacementAttribute i ett korn.

Aktiveringsbaserad placering

Den här placeringsstrategin avser att placera nya kornaktiveringar på den minst hårt belastade servern baserat på antalet nyligen upptagna korn. Den innehåller en mekanism där alla servrar regelbundet publicerar sitt totala aktiveringsantal till alla andra servrar. Placeringschefen väljer sedan en server som förväntas ha minst aktiveringar genom att undersöka det senast rapporterade aktiveringsantalet och förutsäga det aktuella aktiveringsantalet baserat på det senaste aktiveringsantalet som gjorts av placeringschefen på den aktuella servern. Chefen väljer flera servrar slumpmässigt när du gör den här förutsägelsen för att undvika att flera separata servrar överbelastar samma server. Som standard väljs två servrar slumpmässigt, men det här värdet kan konfigureras via ActivationCountBasedPlacementOptions.

Den här algoritmen baseras på avhandlingen The Power of Two Choices in Randomized Load Balancing av Michael David Mitzenmacheroch används även i Nginx för distribuerad belastningsutjämning, enligt beskrivningen i artikeln NGINX och "Power of Two Choices" Load-Balancing Algorithm.

Den här placeringsstrategin konfigureras genom att lägga till ActivationCountBasedPlacementAttribute i ett korn.

Placering av tillståndslös arbetare

Tillståndslös arbetstagarplacering är en särskild placeringsstrategi som används av stateless worker grains. Den här placeringen fungerar nästan identiskt med PreferLocalPlacement förutom att varje server kan ha flera aktiveringar av samma korn och kornet inte är registrerat i kornkatalogen eftersom det inte finns något behov.

Den här placeringsstrategin konfigureras genom att lägga till StatelessWorkerAttribute i ett korn.

Silobaserad placering efter roll

En deterministisk placeringsstrategi som placerar korn på silor med en specifik roll. Den här placeringsstrategin konfigureras genom att lägga till SiloRoleBasedPlacementAttribute i ett korn.

Resursoptimerad placering

Den resursoptimerade placeringsstrategin försöker optimera klusterresurser genom att balansera kornaktiveringar mellan silor baserat på tillgängligt minne och CPU-användning. Den tilldelar vikter till körningsstatistik för att prioritera olika resurser och beräknar en normaliserad poäng för varje silo. Silon med lägst poäng väljs för kommande aktivering. Normalisering säkerställer att varje egenskap bidrar proportionellt till den övergripande poängen. Vikter kan justeras via ResourceOptimizedPlacementOptions baserat på användarspecifika krav och prioriteringar för olika resurser.

Därtill gör den här placeringsstrategin det möjligt att skapa en starkare preferens för den lokala silon (den som fick begäran om att göra en ny placering) att väljas som mål för aktiveringen. Detta styrs via egenskapen LocalSiloPreferenceMargin som ingår i alternativen.

Dessutom ger en online-, anpassningsbar-algoritm en utjämningseffekt som undviker snabba signalfall genom att omvandla den till en polynomliknande sönderfallsprocess. Detta är särskilt viktigt för CPU-användning och bidrar totalt sett till att undvika resursmättnad i silona, särskilt de som nyligen har anslutits.

Den här algoritmen baseras på: Resursbaserad placering med kooperativ filtrering av Kalman med dubbla lägen

Den här placeringsstrategin konfigureras genom att lägga till ResourceOptimizedPlacementAttribute i ett korn.

Välj en placeringsstrategi

Om du väljer lämplig strategi för kornplacering, utöver de standardvärden som Orleans tillhandahåller, krävs övervakning och utvecklarutvärdering. Valet av placeringsstrategi bör baseras på appens storlek och komplexitet, arbetsbelastningsegenskaper och distributionsmiljö.

Slumpmässig placering förlitar sig på lagen om stora tal, så det är vanligtvis en bra standard när det finns en oförutsägbar belastning spridd över ett stort antal korn (10 000 plus).

Aktiveringsbaserad placering har också ett slumpmässigt element i sig, som förlitar sig på principen Power of Two Choices, vilken ofta används som algoritm för distribuerad belastningsutjämning och används i populära lastutjämnare. Silos publicerar ofta körningsstatistik för andra silor i klustret, inklusive:

  • Tillgängligt minne, totalt fysiskt minne och minnesanvändning.
  • CPU-användning.
  • Totalt antal aktiveringar och senaste aktiva aktiveringsantal.
    • Ett skjutfönster med aktiveringar som var aktiva under de senaste sekunderna, som ibland kallas aktiveringsarbetsuppsättningen.

Från den här statistiken används endast aktiveringsantalet för att fastställa belastningen på en viss silo.

I slutändan bör du experimentera med olika strategier och övervaka prestandamått för att fastställa den bästa passformen. Genom att välja rätt strategi för kornplacering kan du optimera prestanda, skalbarhet och kostnadseffektivitet för dina Orleans appar.

Konfigurera standardplaceringsstrategin

Orleans använder slumpmässig placering om inte standardvärdet åsidosätts. Standardplaceringsstrategin kan åsidosättas genom att registrera en implementering av PlacementStrategy under konfigurationen:

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

Konfigurera placeringsstrategin för ett korn

Placeringsstrategin för en korntyp konfigureras genom att lägga till lämpligt attribut i kornklassen. Relevanta attribut anges i avsnitten placeringsstrategier.

Exempel på anpassad placeringsstrategi

Definiera först en klass som implementerar IPlacementDirector-gränssnittet, vilket kräver en enda metod. I det här exemplet antar vi att du har en definierad funktion GetSiloNumber som returnerar ett silonummer utifrån Guid av det korn som ska skapas.

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]);
    }
}

Sedan måste du definiera två klasser för att tillåta att kornklasser tilldelas till strategin:

[Serializable]
public sealed class SamplePlacementStrategy : PlacementStrategy
{
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public sealed class SamplePlacementStrategyAttribute : PlacementAttribute
{
    public SamplePlacementStrategyAttribute() :
        base(new SamplePlacementStrategy())
    {
    }
}

Tagga sedan bara alla kornklasser som du vill använda den här strategin med attributet:

[SamplePlacementStrategy]
public class MyGrain : Grain, IMyGrain
{
    // ...
}

Och slutligen registrerar du strategin när du skapar 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.AddPlacementDirector<SamplePlacementStrategy, SamplePlacementStrategyFixedSiloDirector>();
}

Ett andra enkelt exempel som visar ytterligare användning av placeringskontexten finns i PreferLocalPlacementDirector i Orleans källdatabasen.