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
auserId
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 sorderId
123 -
customerId
421 sorderId
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
, IDistributedCache
a 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ímAddHybridCache(...)
) například ve výchozím nastavení omezuje klíče na 1024 znaků. Toto číslo je možné konfigurovat prostřednictvímHybridCacheOptions.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ímAddHybridCache(...)
) 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:
- třída HybridCacheOptions
- HybridCacheEntryOptions třída.
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áteAddStackExchangeRedisCache
a 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í.
- Problém s GitHubem dotnet/aspnetcore #54647
-
HybridCache
zdrojového kódu