Sdílet prostřednictvím


Knihovna HybridCache v ASP.NET Core

Tento článek vysvětluje, jak nakonfigurovat a používat knihovnu HybridCache v aplikaci ASP.NET Core. Úvod do knihovny najdete v části HybridCache Přehled ukládání do mezipaměti.

Získejte knihovnu

Nainstalujte balíček Microsoft.Extensions.Caching.Hybrid.

dotnet add package Microsoft.Extensions.Caching.Hybrid

Registrace služby

Přidejte službu HybridCache do kontejneru vkládání závislostí (DI) voláním AddHybridCache:

// Add services to the container.
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthorization();

builder.Services.AddHybridCache();

Předchozí kód zaregistruje HybridCache službu s výchozími možnostmi. Rozhraní API pro registraci může také konfigurovat možnosti a serializaci.

Získání a uložení položek mezipaměti

Služba HybridCache poskytuje metodu GetOrCreateAsync se dvěma přetíženími, přičemž přebírá klíč a:

  • Tovární metoda.
  • Stav a metoda továrny

Metoda používá klíč k pokusu o načtení objektu z primární mezipaměti. Pokud se položka v primární mezipaměti nenajde (chybí mezipaměť), zkontroluje sekundární mezipaměť, pokud je nakonfigurovaná. Pokud tam nenajde data (další neúspěšný pokus v mezipaměti), zavolá tovární metodu pro získání objektu ze zdroje dat. Pak uloží objekt do primární i sekundární mezipaměti. Metoda továrny se nikdy nevolá, pokud se objekt nachází v primární nebo sekundární mezipaměti (zásah do mezipaměti).

Služba HybridCache zajišťuje, že pro daný klíč volá metodu továrny pouze jeden souběžný volající a všichni ostatní volající čekají na výsledek tohoto volání. Parametr CancellationToken předaný do GetOrCreateAsync představuje celkové zrušení všech souběžných volajících.

GetOrCreateAsync Hlavní přetížení

Pro většinu scénářů se doporučuje bezstavové přetížení GetOrCreateAsync . Kód k jeho volání je relativně jednoduchý. Tady je příklad:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
            cancellationToken: token
        );
    }

    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Pokyny pro klíče mezipaměti

key předaný GetOrCreateAsync musí jedinečně identifikovat data uložená v mezipaměti:

  • Pokud jde o hodnoty identifikátoru použité k načtení těchto dat z jeho zdroje.
  • Z hlediska jiných dat uložených v mezipaměti v aplikaci.

Oba typy jedinečnosti jsou obvykle zajištěny pomocí zřetězení řetězců, aby byl jeden řetězec klíče složený z různých částí zřetězený do jednoho řetězce. Příklad:

cache.GetOrCreateAsync($"/orders/{region}/{orderId}", ...);

nebo

cache.GetOrCreateAsync($"user_prefs_{userId}", ...);

Je zodpovědností volajícího zajistit, aby bylo schéma klíčů platné a nemohlo způsobit zmatení dat.

Doporučujeme nepoužívat vstup externího uživatele v klíči mezipaměti. Nepoužívejte například nezpracované string hodnoty z uživatelského rozhraní jako součást klíče mezipaměti. Tyto klíče by mohly umožnit pokusy o škodlivý přístup nebo by se mohly použít při útoku do služby prostřednictvím nasycení mezipaměti daty, které mají zbytečné klíče generované z náhodných řetězců. V předchozích platných příkladech jsou data objednávek a data uživatelských preferencí jasně odlišná.

  • orderid a userId jsou interně generované identifikátory.
  • region může být výčtem nebo řetězcem z předdefinovaného seznamu známých oblastí.

U tokenů, jako jsou / nebo _, není žádný význam. Celá hodnota klíče je považována za neprůznačný řetězec. V tomto případě byste mohli vynechat / a _ beze změny způsobu fungování mezipaměti, ale oddělovač se obvykle používá k zabránění nejednoznačnosti – například $"order{customerId}{orderId}" může způsobit nejasnost mezi:

  • customerId 42 s orderId 123
  • customerId 421 s orderId 23

(obojí by vygenerovalo klíč mezipaměti order42123)

Tyto pokyny platí stejně pro všechna rozhraní API mezipaměti založená na string, jako jsou HybridCache, IDistributedCachea IMemoryCache.

Všimněte si, že syntaxe vloženého interpolovaného řetězce ($"..." v dříve uvedených příkladech platných klíčů) se nachází přímo ve volání GetOrCreateAsync. Tato syntaxe se doporučuje při použití HybridCache, protože umožňuje plánovaná budoucí vylepšení, která obcházejí potřebu přidělit string pro klíč v mnoha scénářích.

Další klíčové aspekty

  • Klíče mohou být omezeny na platné maximální délky. Výchozí implementace HybridCache (prostřednictvím AddHybridCache(...)) například ve výchozím nastavení omezuje klíče na 1024 znaků. Toto číslo je možné konfigurovat prostřednictvím HybridCacheOptions.MaximumKeyLength, přičemž delší klíče obcházejí mechanismy mezipaměti, aby se zabránilo jejich přeplnění.
  • Klíče musí být platné sekvence Unicode. Pokud jsou předány neplatné sekvence Unicode, chování není definováno.
  • Při použití sekundární mezipaměti mimo proces, jako je například IDistributedCache, může konkrétní implementace back-endu uplatňovat další omezení. Jako hypotetický příklad může konkrétní back-end používat logiku klíče bez rozlišování malých a velkých písmen. Výchozí HybridCache (prostřednictvím AddHybridCache(...)) tento scénář detekuje, aby se předešlo matoucím útokům, ale může to vést k tomu, že kolizní klíče budou přepsány nebo vyřazeny dříve, než bylo očekáváno.

GetOrCreateAsync Alternativní přetížení

Alternativní přetížení může snížit některé režijní náklady z zachycených proměnných a zpětných volání na instanci, ale na úkor složitějšího kódu. U většiny scénářů zvýšení výkonu nepřeváží složitost kódu. Tady je příklad, který používá alternativní přetížení:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            (name, id, obj: this),
            static async (state, token) =>
            await state.obj.GetDataFromTheSourceAsync(state.name, state.id, token),
            cancellationToken: token
        );
    }

    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Metoda SetAsync

V mnoha scénářích je rozhraní API GetOrCreateAsync tím jediným, které je potřeba. Kromě toho HybridCache musí SetAsync objekt uložit do mezipaměti, aniž byste se ho nejdřív pokusili načíst.

Odebrání položek mezipaměti podle klíče

Když se podkladová data pro položku mezipaměti před vypršením platnosti změní, odeberte ji explicitně voláním RemoveAsync klíče k položce. Přetížení umožňuje zadat kolekci klíčových hodnot.

Když je položka odebrána, odebere se z primární i sekundární mezipaměti.

Odebrání položek mezipaměti podle značky

Značky lze použít k seskupení položek mezipaměti a jejich zneplatnění.

Nastavte značky při volání GetOrCreateAsync, jak je znázorněno v následujícím příkladu:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        var tags = new List<string> { "tag1", "tag2", "tag3" };
        var entryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromMinutes(1),
            LocalCacheExpiration = TimeSpan.FromMinutes(1)
        };
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
            entryOptions,
            tags,
            cancellationToken: token
        );
    }
    
    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Odeberte všechny položky pro zadanou značku zavoláním RemoveByTagAsync s hodnotou značky. Přetížení umožňuje zadat kolekci hodnot značek.

Když je položka odebrána, odebere se z primární i sekundární mezipaměti.

Možnosti

Metodu AddHybridCache lze použít ke konfiguraci globálních výchozích hodnot. Následující příklad ukazuje, jak nakonfigurovat některé z dostupných možností:

// Add services to the container.
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

builder.Services.AddHybridCache(options =>
    {
        options.MaximumPayloadBytes = 1024 * 1024;
        options.MaximumKeyLength = 1024;
        options.DefaultEntryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromMinutes(5),
            LocalCacheExpiration = TimeSpan.FromMinutes(5)
        };
    });

Metoda GetOrCreateAsync může také přijmout HybridCacheEntryOptions objekt, který přepíše globální výchozí hodnoty pro určitou položku mezipaměti. Tady je příklad:

public class SomeService(HybridCache cache)
{
    private HybridCache _cache = cache;

    public async Task<string> GetSomeInfoAsync(string name, int id, CancellationToken token = default)
    {
        var tags = new List<string> { "tag1", "tag2", "tag3" };
        var entryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromMinutes(1),
            LocalCacheExpiration = TimeSpan.FromMinutes(1)
        };
        return await _cache.GetOrCreateAsync(
            $"{name}-{id}", // Unique key to the cache entry
            async cancel => await GetDataFromTheSourceAsync(name, id, cancel),
            entryOptions,
            tags,
            cancellationToken: token
        );
    }
    
    public async Task<string> GetDataFromTheSourceAsync(string name, int id, CancellationToken token)
    {
        string someInfo = $"someinfo-{name}-{id}";
        return someInfo;
    }
}

Další informace o možnostech najdete ve zdrojovém kódu:

Omezení

Následující vlastnosti HybridCacheOptions umožňují konfigurovat limity, které platí pro všechny položky mezipaměti:

  • MaximumPayloadBytes – maximální velikost položky mezipaměti. Výchozí hodnota je 1 MB. Zaprotokolují se pokusy o uložení hodnot nad touto velikostí a hodnota není uložená v mezipaměti.
  • MaximumKeyLength – maximální délka klíče mezipaměti. Výchozí hodnota je 1024 znaků. Zaprotokolují se pokusy o uložení hodnot nad touto velikostí a hodnota není uložená v mezipaměti.

Serializace

Použití sekundární mezipaměti mimo proces vyžaduje serializaci. Serializace se konfiguruje jako součást registrace HybridCache služby. Serializátory specifické pro konkrétní typ i pro obecné účely lze konfigurovat pomocí metod AddSerializer a AddSerializerFactory, které jsou zřetězené z volání AddHybridCache. Ve výchozím nastavení knihovna zpracovává string a byte[] interně a používá System.Text.Json pro všechno ostatní. HybridCache může také používat jiné serializátory, jako je protobuf nebo XML.

Následující příklad nakonfiguruje službu tak, aby používala serializátor protobuf specifický pro typ:

// Add services to the container.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

builder.Services.AddHybridCache(options =>
    {
        options.DefaultEntryOptions = new HybridCacheEntryOptions
        {
            Expiration = TimeSpan.FromSeconds(10),
            LocalCacheExpiration = TimeSpan.FromSeconds(5)
        };
    }).AddSerializer<SomeProtobufMessage, 
        GoogleProtobufSerializer<SomeProtobufMessage>>();

Následující příklad nakonfiguruje službu tak, aby používala serializátor protobuf pro obecné účely, který dokáže zpracovat mnoho typů protobuf:

// Add services to the container.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthorization();

builder.Services.AddHybridCache(options =>
{
    options.DefaultEntryOptions = new HybridCacheEntryOptions
    {
        Expiration = TimeSpan.FromSeconds(10),
        LocalCacheExpiration = TimeSpan.FromSeconds(5)
    };
}).AddSerializerFactory<GoogleProtobufSerializerFactory>();

Sekundární mezipaměť vyžaduje úložiště dat, jako je Redis nebo SqlServer. Použití služby Azure Cache for Redis, například:

  • Nainstalujte balíček Microsoft.Extensions.Caching.StackExchangeRedis.

  • Vytvořte instanci Azure Cache for Redis.

  • Získejte připojovací řetězec pro připojení k instanci Redis. Vyhledejte připojovací řetězec tak, že na stránce Přehled na webu Azure Portal vyberete Zobrazit přístupové klíče.

  • Uložte připojovací řetězec v konfiguraci aplikace. Například použijte soubor uživatelských tajemství, který vypadá jako následující JSON, s připojovacím řetězcem v části ConnectionStrings. Nahraďte <the connection string> skutečným připojovacím řetězcem.

    {
      "ConnectionStrings": {
        "RedisConnectionString": "<the connection string>"
      }
    }
    
  • Zaregistrujte v DI implementaci IDistributedCache, kterou poskytuje balíček Redis. Uděláte to tak, že zavoláte AddStackExchangeRedisCachea předáte připojovací řetězec. Příklad:

    builder.Services.AddStackExchangeRedisCache(options =>
    {
        options.Configuration = 
            builder.Configuration.GetConnectionString("RedisConnectionString");
    });
    
  • Implementace Redis IDistributedCache je teď dostupná z kontejneru DI aplikace. HybridCache používá ho jako sekundární mezipaměť a používá pro ni serializátor nakonfigurovaný.

Další informace naleznete v ukázkové aplikaci serializace HybridCache.

Ukládání do mezipaměti

Ve výchozím nastavení HybridCache se používá MemoryCache pro primární úložiště mezipaměti. Položky mezipaměti se ukládají v procesu, takže každý server má samostatnou mezipaměť, která se ztratí při každém restartování procesu serveru. Pro sekundární mimoprocesové úložiště, jako je Redis nebo SQL Server, HybridCache používá nakonfigurovanou IDistributedCache implementaci( pokud existuje). I bez implementace IDistributedCache služba HybridCache ale stále poskytuje ukládání do mezipaměti v procesu a ochranu proti lavinovému efektu.

Poznámka

Při zneplatňování položek mezipaměti podle klíče nebo značek se tyto položky zneplatní jak na aktuálním serveru, tak v sekundárním úložišti mimo proces. Mezipaměť v paměti na jiných serverech však není ovlivněna.

Optimalizace výkonu

Pokud chcete optimalizovat výkon, nakonfigurujte HybridCache, aby opakoval použití objektů a vyhněte se byte[] alokacím.

Opakované použití objektů

Opětovným použitím instancí může HybridCache snížit režii alokace CPU a objektů spojenou s deserializací při každém volání. To může vést ke zlepšení výkonu ve scénářích, kdy jsou objekty uložené v mezipaměti velké nebo často přístupné.

V typickém existujícím kódu, který používá IDistributedCache, každé načtení objektu z mezipaměti má za následek deserializaci. Toto chování znamená, že každý souběžný volající získá samostatnou instanci objektu, která nemůže komunikovat s jinými instancemi. Výsledkem je bezpečnost vláken, protože neexistuje riziko souběžných úprav stejné instance objektu.

Vzhledem k tomu, že mnoho HybridCache využití bude přizpůsobeno stávajícímu IDistributedCache kódu, HybridCache zachovává toto chování ve výchozím nastavení, aby nedocházelo k problémům se souběžností. Objekty jsou však ze své podstaty zabezpečené pro přístup z více vláken, pokud:

  • Jedná se o neměnné typy.
  • Kód je nezmění.

V takových případech informujte HybridCache , že je bezpečné opakovaně používat instance pomocí:

  • Označení typu jako sealed. Klíčové sealed slovo v jazyce C# znamená, že třídu nelze dědit.
  • Použití atributu [ImmutableObject(true)] na typ. Atribut [ImmutableObject(true)] označuje, že stav objektu nelze po vytvoření změnit.

Vyhněte se byte[] přidělování

HybridCache také poskytuje volitelná rozhraní API pro implementace IDistributedCache, čímž se vyhne přidělování byte[]. Tuto funkci implementují verze preview balíčků Microsoft.Extensions.Caching.StackExchangeRedis a Microsoft.Extensions.Caching.SqlServer. Další informace najdete v tématu IBufferDistributedCache. Tady jsou příkazy rozhraní příkazového řádku .NET pro instalaci balíčků:

dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
dotnet add package Microsoft.Extensions.Caching.SqlServer

Vlastní implementace HybridCache

Konkrétní implementace HybridCache abstraktní třídy je zahrnuta ve sdílené architektuře a je poskytována prostřednictvím injektáže závislostí. Vývojáři ale mohou poskytovat nebo využívat vlastní implementace rozhraní API, například FusionCache.

Kompatibilita

Knihovna HybridCache podporuje starší vlastnosti runtime .NET až do .NET Framework 4.7.2 a .NET Standard 2.0.

Další materiály

Další informace o HybridCache najdete v následujících zdrojích informací.