Sdílet prostřednictvím


Trvalost zrn

Zrna mohou mít k sobě přidružená několik pojmenovaných trvalých datových objektů. Tyto stavové objekty jsou načteny z úložiště při aktivaci zrnitosti, aby byly během požadavků k dispozici. Trvalost zrn používá rozšiřitelný model modulu plug-in, aby bylo možné použít poskytovatele úložiště pro každou databázi. Tento model trvalosti je navržen pro jednoduchost a není určen k pokrytí všech vzorů přístupu k datům. Zrna mohou také přistupovat přímo k databázím, aniž by používali model trvalosti zrnitosti.

Ve výše uvedeném diagramu má UserGrain stav profilu a stav košíku , z nichž každý je uložený v samostatném systému úložiště.

Cíle

  1. Více pojmenovaných trvalých datových objektů na zrno.
  2. Několik nakonfigurovaných poskytovatelů úložiště, z nichž každá může mít jinou konfiguraci a je zajištěno jiným systémem úložiště.
  3. poskytovatelé Storage mohou být vyvinuti a publikováni komunitou.
  4. poskytovatelé Storage mají úplnou kontrolu nad tím, jak ukládají data o stavu zrnitosti do trvalého záložního úložiště. Corollary: Orleans neposkytuje komplexní řešení úložiště ORM, ale místo toho umožňuje vlastním poskytovatelům úložiště podporovat konkrétní požadavky na ORM jako a v případě potřeby.

Balíčky

Poskytovatelé úložiště Orleans na zrno najdete na NuGet. Mezi úředně udržované balíčky patří:

rozhraní API

Zrna v interakci s jejich trvalým stavem, který TState používá IPersistentState<TState> typ serializovatelný stav:

public interface IPersistentState<TState> where TState : new()
{
    TState State { get; set; }
    string Etag { get; }
    Task ClearStateAsync();
    Task WriteStateAsync();
    Task ReadStateAsync();
}

IPersistentState<TState>Instance jsou vloženy do zrnitosti jako parametry konstruktoru. Tyto parametry lze opatřit pomocí PersistentStateAttribute atributu k identifikaci názvu vloženého stavu a názvu poskytovatele úložiště, který jej poskytuje. Následující příklad ukazuje to vložením dvou pojmenovaných stavů do UserGrain konstruktoru:

public class UserGrain : Grain, IUserGrain
{
    private readonly IPersistentState<ProfileState> _profile;
    private readonly IPersistentState<CartState> _cart;

    public UserGrain(
        [PersistentState("profile", "profileStore")] IPersistentState<ProfileState> profile,
        [PersistentState("cart", "cartStore")] IPersistentState<CartState> cart)
    {
        _profile = profile;
        _cart = cart;
    }
}

Různé typy zrnitosti můžou používat jiné nakonfigurované poskytovatele úložiště, i když oba mají stejný typ. například dvě různé instance poskytovatele služby Azure Table Storage připojené k různým účtům Azure Storage.

Číst stav

Po aktivaci zrnitosti se automaticky přečte stav zrn, ale zrna jsou zodpovědná za explicitní aktivaci zápisu pro libovolný změněný stav zrn v případě potřeby.

Pokud si v případě zrn přeje explicitně znovu načíst nejnovější stav tohoto zrnitosti ze záložního úložiště, zrna by měla zavolat ReadStateAsync metodu. Tato operace znovu načte stav zrnitosti z trvalého úložiště prostřednictvím poskytovatele úložiště a předchozí kopie stavu v paměti bude při TaskReadStateAsync() dokončení operace přepsána a nahrazena.

Hodnota stavu je k dispozici pomocí State Vlastnosti. Například následující metoda přistupuje ke stavu profilu deklarovanému v kódu výše:

public Task<string> GetNameAsync() => Task.FromResult(_profile.State.Name);

Při normálním provozu není nutné volat ReadStateAsync() , stav je načten automaticky během aktivace. ReadStateAsync()Dá se ale použít k aktualizaci stavu, který se upraví externě.

Podrobnosti o mechanismech zpracování chyb najdete v části režimy selhání níže.

Stav zápisu

Stav lze upravit prostřednictvím State Vlastnosti. Upravený stav není automaticky trvalý. Místo toho se vývojář rozhodne, kdy se má zachovat stav, voláním WriteStateAsync metody. Například následující metoda aktualizuje vlastnost v State a uchovává aktualizovaný stav:

public async Task SetNameAsync(string name)
{
    _profile.State.Name = name;
    await _profile.WriteStateAsync();
}

V koncepčním případě bude Orleans modul runtime pořizovat hlubokou kopii datového objektu stavu zrnitosti, který se použije během jakýchkoli operací zápisu. V rámci pokrývá modul runtime může použít pravidla optimalizace a heuristické metody k tomu, aby se předešlo provádění některých nebo všech hlubokých kopií za určitých okolností za předpokladu, že se zachovají očekávané sémantiky logických izolací.

Podrobnosti o mechanismech zpracování chyb najdete v části režimy selhání níže.

Vymazat stav

ClearStateAsyncMetoda vymaže stav zrnitosti v úložišti. V závislosti na poskytovateli Tato operace může volitelně odstranit stav zrn zcela.

Začínáme

Aby mohla zrna používat trvalost, musí být v silu nakonfigurovaný poskytovatel úložiště.

Nejdřív nakonfigurujte poskytovatele úložiště, jednu pro stav profilu a jeden pro stav košíku:

var host = new HostBuilder()
    .UseOrleans(siloBuilder =>
    {
        siloBuilder.AddAzureTableGrainStorage(
            name: "profileStore",
            configureOptions: options =>
            {
                // Use JSON for serializing the state in storage
                options.UseJson = true;

                // Configure the storage connection key
                options.ConnectionString =
                    "DefaultEndpointsProtocol=https;AccountName=data1;AccountKey=SOMETHING1";
            })
            .AddAzureBlobGrainStorage(
                name: "cartStore",
                configureOptions: options =>
                {
                    // Use JSON for serializing the state in storage
                    options.UseJson = true;

                    // Configure the storage connection key
                    options.ConnectionString =
                        "DefaultEndpointsProtocol=https;AccountName=data2;AccountKey=SOMETHING2";
                });
    })
    .Build();

Teď, když je poskytovatel úložiště nakonfigurovaný s názvem "profileStore" , můžeme k tomuto poskytovateli přistupovat z zrnitosti.

Trvalý stav lze přidat do zrnitého dvěma primárními způsoby:

  1. IPersistentState<TState>Vložením do konstruktoru zrnitosti.
  2. Děděním z Grain<TGrainState> .

Doporučený způsob, jak přidat úložiště do zrnitosti, je IPersistentState<TState> vložení do konstruktoru zrnitosti s přidruženým [PersistentState("stateName", "providerName")] atributem. Podrobnosti o najdete níže. Tato metoda je stále podporovaná, ale je považována za starší.

Deklarovat třídu pro uložení stavu zrnitosti:

[Serializable]
public class ProfileState
{
    public string Name { get; set; }

    public Date DateOfBirth
}

Vložit IPersistentState<ProfileState> do konstruktoru zrnitosti:

public class UserGrain : Grain, IUserGrain
{
    private readonly IPersistentState<ProfileState> _profile;

    public UserGrain(
        [PersistentState("profile", "profileStore")]
        IPersistentState<ProfileState> profile)
    {
        _profile = profile;
    }
}

Poznámka

Stav profilu nebude načten v době, kdy je vložen do konstruktoru, takže jeho přístup je v tuto chvíli neplatný. Stav bude načten před OnActivateAsync voláním.

Teď, když má zrnitý trvalý stav, můžeme přidat metody pro čtení a zápis stavu:

public class UserGrain : Grain, IUserGrain
    {
    private readonly IPersistentState<ProfileState> _profile;

    public UserGrain(
        [PersistentState("profile", "profileStore")]
        IPersistentState<ProfileState> profile)
    {
        _profile = profile;
    }

    public Task<string> GetNameAsync() => Task.FromResult(_profile.State.Name);

    public async Task SetNameAsync(string name)
    {
        _profile.State.Name = name;
        await _profile.WriteStateAsync();
    }
}

Režimy selhání pro operace trvalosti

Režimy selhání pro operace čtení

Chyby vrácené poskytovatelem úložiště během počátečního čtení dat stavu pro tuto konkrétní zrnitost selžou operaci aktivace pro tuto zrnitost; v takovém případě nebude k dispozici žádné volání metody zpětného volání pro životní cyklus této zrnitosti . Původní požadavek na zrno, který způsobil aktivaci, se vrátí volajícímu stejným způsobem jako jakékoli jiné selhání při aktivaci zrnitosti. Selhání zjištěné poskytovatelem úložiště při čtení dat stavu pro konkrétní zrnitost budou mít za následek výjimku ReadStateAsync()Task . Zrnitost se může rozhodnout zpracovat nebo ignorovat Task výjimku, stejně jako jakoukoli jinou Task v Orleans.

Všechny pokusy o odeslání zprávy do zrnitosti, které se nepodařilo načíst při spuštění v době spuštění, protože konfigurace poskytovatele chybějícího nebo chybného zprostředkovatele úložiště vrátí trvalou chybu BadProviderConfigException .

Režimy selhání pro operace zápisu

Selhání zjištěné poskytovatelem úložiště při zápisu dat stavu pro určitou zrnitost způsobí výjimku vyvolanou WriteStateAsync()Task v. Obvykle to znamená, že výjimka volání zrnitou bude vrácena zpět volajícímu klienta za předpokladu, že WriteStateAsync()Task je správně zřetězena k konečnému návratu Task pro tuto metodu zrnitosti. Je ale možné, že v některých pokročilých scénářích napíšete kód zrnitosti, který konkrétně zpracovává tyto chyby při zápisu, stejně jako můžou nakládat s dalšími chybami Task .

Zrna, která provádějí zpracování chyb/kódu obnovení, musí zachytit výjimky/chyby Task s a znovu je vyvolat, aby signalizují, že úspěšně zpracovaly chybu zápisu.

Doporučení

Použít serializaci JSON nebo jiný formát serializace odolný proti verzím

Vývoj kódu a často zahrnuje i typy úložišť. Aby bylo možné tyto změny přizpůsobit, je třeba nakonfigurovat vhodný serializátor. Pro většinu poskytovatelů UseJson úložiště je k dispozici možnost nebo podobná použití formátu JSON jako serializace. Ujistěte se, že při vývoji kontraktů dat, které už jsou uložená data, se spustitelný i nadále.

Přidání úložiště do zrnitého pomocí zrnitého < TState >

Důležité

Použití Grain<T> pro přidání úložiště do zrnitosti se považuje za Grain<T> funkce: zrnité úložiště byste měli přidat pomocí IPersistentState<T> postupu popsaného výše.

Třídy zrnitosti, které dědí z Grain<T> (kde T je datový typ stavu specifický pro aplikaci, který musí být trvalý), budou automaticky načteny ze zadaného úložiště.

Tato zrna jsou označená StorageProviderAttribute jako pojmenovaná instance poskytovatele úložiště, která se má použít pro čtení nebo zápis dat stavu pro tuto zrnitost.

[StorageProvider(ProviderName="store1")]
public class MyGrain : Grain<MyGrainState>, /*...*/
{
  /*...*/
}

Grain<T>Základní třída definovala následující metody pro podtřídy, které mají být volány:

protected virtual Task ReadStateAsync() { /*...*/ }
protected virtual Task WriteStateAsync() { /*...*/ }
protected virtual Task ClearStateAsync() { /*...*/ }

Chování těchto metod odpovídá jejich protějškům ve IPersistentState<TState> výše definovaném.

Vytvoření poskytovatele úložiště

Existují dvě části rozhraní API trvalosti stavu: rozhraní API vystavené zrnitému přes IPersistentState<T> nebo Grain<T> a rozhraní API poskytovatele úložiště, které je na střed IGrainStorage – rozhraní, které poskytovatelé úložiště musí implementovat:

/// <summary>
/// Interface to be implemented for a storage able to read and write Orleans grain state data.
/// </summary>
public interface IGrainStorage
{
    /// <summary>Read data function for this storage instance.</summary>
    /// <param name="grainType">Type of this grain [fully qualified class name]</param>
    /// <param name="grainReference">Grain reference object for this grain.</param>
    /// <param name="grainState">State data object to be populated for this grain.</param>
    /// <returns>Completion promise for the Read operation on the specified grain.</returns>
    Task ReadStateAsync(
        string grainType, GrainReference grainReference, IGrainState grainState);

    /// <summary>Write data function for this storage instance.</summary>
    /// <param name="grainType">Type of this grain [fully qualified class name]</param>
    /// <param name="grainReference">Grain reference object for this grain.</param>
    /// <param name="grainState">State data object to be written for this grain.</param>
    /// <returns>Completion promise for the Write operation on the specified grain.</returns>
    Task WriteStateAsync(
        string grainType, GrainReference grainReference, IGrainState grainState);

    /// <summary>Delete / Clear data function for this storage instance.</summary>
    /// <param name="grainType">Type of this grain [fully qualified class name]</param>
    /// <param name="grainReference">Grain reference object for this grain.</param>
    /// <param name="grainState">Copy of last-known state data object for this grain.</param>
    /// <returns>Completion promise for the Delete operation on the specified grain.</returns>
    Task ClearStateAsync(
        string grainType, GrainReference grainReference, IGrainState grainState);
}

Vytvořte vlastního poskytovatele úložiště implementací tohoto rozhraní a registrací této implementace. Příklad existující implementace poskytovatele úložiště najdete v tématu AzureBlobGrainStorage .

sémantika poskytovatele Storage

Neprůhledná hodnota specifická Etag pro poskytovatele ( string ) Etag být nastavena poskytovatelem úložiště jako součást metadat stavu zrnitosti vyplněných při čtení stavu. Někteří poskytovatelé můžou tuto možnost ponechat, jako null kdyby nepoužívali Etag s.

Jakýkoli pokus o provedení operace zápisu, když poskytovatel úložiště zjistí Etag porušení omezení, Etag způsobit chybu zápisu Task s přechodnou chybou InconsistentStateException a zabalením základní výjimky úložiště.

public class InconsistentStateException : OrleansException
{
    public InconsistentStateException(
    string message,
    string storedEtag,
    string currentEtag,
    Exception storageException)
        : base(message, storageException)
    {
        StoredEtag = storedEtag;
        CurrentEtag = currentEtag;
    }

    public InconsistentStateException(
        string storedEtag,
        string currentEtag,
        Exception storageException)
        : this(storageException.Message, storedEtag, currentEtag, storageException)
    {
    }

    /// <summary>The Etag value currently held in persistent storage.</summary>
    public string StoredEtag { get; }

    /// <summary>The Etag value currently held in memory, and attempting to be updated.</summary>
    public string CurrentEtag { get; }
}

Všechny ostatní stavy selhání operace úložiště musí způsobit, že vrácená výjimka je poškozená s výjimkou, která indikuje základní problém úložiště. V mnoha případech může být tato výjimka vrácena volajícímu, který aktivoval operaci úložiště, voláním metody v zrnitosti. Je důležité zvážit, zda volající bude moci tuto výjimku deserializovat. Například klient nemusí načíst konkrétní knihovnu trvalosti obsahující typ výjimky. Z tohoto důvodu je vhodné převést výjimky na výjimky, které lze rozšířit zpět volajícímu.

Mapování dat

Jednotliví poskytovatelé úložiště by měli rozhodnout, jak nejlépe uložit stav zrnitosti – objekt BLOB (různé formáty/serializované formuláře) nebo sloupce podle pole jsou zřejmé možnosti.

Registrace poskytovatele úložiště

Modul runtime Orleans vyřeší poskytovatele úložiště od poskytovatele služeb ( IServiceProvider ) při vytvoření zrnitosti. Modul runtime vyřeší instanci IGrainStorage . Pokud je poskytovatel úložiště pojmenován například pomocí [PersistentState(stateName, storageName)] atributu, bude přeložena pojmenovaná instance IGrainStorage .

Chcete-li zaregistrovat pojmenovanou instanci IGrainStorage , použijte AddSingletonNamedService metodu rozšíření podle příkladu IGrainStorage.