Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule wyjaśniono, jak skonfigurować bibliotekę HybridCache i używać jej w aplikacji ASP.NET Core. Aby zapoznać się z wprowadzeniem do biblioteki, zobacz w sekcji HybridCache.
Pobierz bibliotekę
Zainstaluj pakiet Microsoft.Extensions.Caching.Hybrid.
dotnet add package Microsoft.Extensions.Caching.Hybrid
Rejestrowanie usługi
Dodaj usługę HybridCache do kontenera wstrzykiwania zależności (DI) poprzez wywołanie AddHybridCache:
// Add services to the container.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthorization();
builder.Services.AddHybridCache();
Powyższy kod rejestruje usługę HybridCache przy użyciu opcji domyślnych. Interfejs API do rejestracji może również skonfigurować opcje i serializację.
Pobieranie i przechowywanie wpisów pamięci podręcznej
Usługa HybridCache udostępnia metodę z dwoma GetOrCreateAsync przeciążeniami, przyjmując jako argument klucz oraz:
- Metoda fabryczna.
- Stan i metoda fabryki.
Metoda używa klucza, aby spróbować pobrać obiekt z podstawowej pamięci podręcznej. Jeśli element nie zostanie znaleziony w podstawowej pamięci podręcznej (brakuje pamięci podręcznej), sprawdza pomocniczą pamięć podręczną, jeśli została skonfigurowana. Jeśli nie znajdzie tam danych (kolejne nietrafienie pamięci podręcznej), wywołuje metodę wytwórczą, aby pobrać obiekt ze źródła danych. Następnie przechowuje obiekt w pamięciach podręcznych podstawowych i pomocniczych. Metoda fabryczna nie jest wywoływana, jeśli obiekt znajduje się w podstawowej lub wtórnej pamięci podręcznej (trafienie do pamięci podręcznej).
HybridCache Usługa zapewnia, że tylko jeden dzwoniący dla danego klucza wywołuje metodę fabryczną, a wszyscy inni czekają na wynik tego wywołania. Przekazany CancellationToken do GetOrCreateAsync reprezentuje łączne anulowanie wszystkich współbieżnych wywołań.
Główne GetOrCreateAsync przeciążenie
Przeciążenie bezstanowe GetOrCreateAsync jest zalecane w przypadku większości scenariuszy. Kod do wywołania jest stosunkowo prosty. Oto przykład:
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;
}
}
Przewodnik dotyczący kluczy pamięci podręcznej
Przekazany key do GetOrCreateAsync musi jednoznacznie zidentyfikować buforowane dane:
- Jeśli chodzi o wartości identyfikatorów używane do pobierania tych danych ze źródła.
- Jeśli chodzi o inne dane buforowane w aplikacji.
Oba typy unikatowości są zwykle zapewniane przy użyciu łączenia ciągów w celu utworzenia pojedynczego ciągu klucza składającego się z różnych części połączonych w jeden ciąg. Na przykład:
cache.GetOrCreateAsync($"/orders/{region}/{orderId}", ...);
lub
cache.GetOrCreateAsync($"user_prefs_{userId}", ...);
Odpowiedzialnością obiektu wywołującego jest upewnienie się, że schemat jest prawidłowy i nie może wprowadzić danych w błąd.
Unikaj używania danych wejściowych użytkownika zewnętrznego bezpośrednio w kluczach pamięci podręcznej. Na przykład nie używaj nieprzetworzonych ciągów z interfejsów użytkownika jako kluczy pamięci podręcznej. Może to spowodować narażenie aplikacji na zagrożenia bezpieczeństwa, takie jak nieautoryzowany dostęp lub ataki typu "odmowa usługi" spowodowane przez zalanie pamięci podręcznej przypadkowymi lub bezsensownymi kluczami. W poprzednich prawidłowych przykładach dane dotyczące kolejności i preferencji użytkownika są wyraźnie oddzielone i używają zaufanych identyfikatorów:
-
orderidiuserIdsą wewnętrznie generowane identyfikatory. -
regionmoże być enumem lub ciągiem z predefiniowanej listy znanych regionów.
Tokeny takie jak / lub _ nie mają znaczenia. Cała wartość klucza jest traktowana jako nieprzezroczysty ciąg identyfikujący. W takim przypadku można pominąć / i _ bez zmiany sposobu działania pamięci podręcznej, ale ogranicznik jest zwykle używany do uniknięcia niejednoznaczności — na przykład $"order{customerId}{orderId}" może powodować zamieszanie między:
-
customerId42 zorderId123 -
customerId421 zorderId23
Oba powyższe przykłady wygenerowałyby klucz order42123pamięci podręcznej .
Te wytyczne dotyczą również dowolnego interfejsu API pamięci podręcznej opartego na string, takiego jak HybridCache, IDistributedCache, i IMemoryCache.
Zwróć uwagę, że składnia interpolowanego ciągu w wierszu ($"..." w poprzednich przykładach prawidłowych kluczy) znajduje się bezpośrednio w wywołaniu GetOrCreateAsync. Ta składnia jest zalecana w przypadku używania HybridCache, ponieważ umożliwia planowane przyszłe ulepszenia, które pomijają konieczność przydzielenia string dla klucza w wielu scenariuszach.
Dodatkowe kluczowe zagadnienia
- Klucze mogą być ograniczone do prawidłowych maksymalnych długości. Na przykład domyślna implementacja
HybridCache(za pośrednictwemAddHybridCache(...)) domyślnie ogranicza klucze do 1024 znaków. Ta liczba jest konfigurowalna za pośrednictwemHybridCacheOptions.MaximumKeyLength, przy czym dłuższe klucze omijają mechanizmy pamięci podręcznej, aby zapobiec nasyceniu. - Klucze muszą być prawidłowymi sekwencjami Unicode. Jeśli przekazano nieprawidłowe sekwencje Unicode, zachowanie jest niezdefiniowane.
- W przypadku korzystania z pomocniczej pamięci podręcznej poza procesem, takiej jak
IDistributedCache, implementacja zaplecza może nakładać dodatkowe ograniczenia. W hipotetycznym przykładzie szczególny system backend może używać logiki klucza ignorującej wielkość liter. Wartość domyślnaHybridCache(za pośrednictwemAddHybridCache(...)) wykrywa ten scenariusz, aby zapobiec atakom pomyłek lub atakom aliasu (przy użyciu równości ciągów bitowych). Jednak w tym scenariuszu nadal mogą wystąpić konflikty kluczy, które zostaną nadpisane lub usunięte wcześniej niż oczekiwano.
Alternatywna wersja przeciążona GetOrCreateAsync
Alternatywne przeciążenie może zmniejszyć obciążenie związane z przechwyconymi zmiennymi i wywołaniami zwrotnymi dla poszczególnych wystąpień, ale kosztem bardziej złożonego kodu. W przypadku większości scenariuszy wzrost wydajności nie przewyższa złożoności kodu. Oto przykład używający alternatywnego przeciążenia:
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
W wielu scenariuszach GetOrCreateAsync jest jedynym interfejsem API wymaganym. Ale HybridCache może SetAsync również przechowywać obiekt w pamięci podręcznej, bez próby jego wcześniejszego pobrania.
Usuń wpisy pamięci podręcznej według klucza
Gdy dane bazowe dla wpisu pamięci podręcznej zmienią się przed jego wygaśnięciem, usuń wpis jawnie, wywołując RemoveAsync z kluczem do wpisu. Przeciążenie umożliwia określenie kolekcji wartości kluczy.
Po usunięciu wpisu zostanie on usunięty zarówno z pamięci podręcznej podstawowej, jak i pomocniczej.
Usuwanie wpisów pamięci podręcznej według tagu
Tagi mogą służyć do grupowania wpisów pamięci podręcznej i unieważniać je razem.
Ustaw tagi podczas wywoływania metody GetOrCreateAsync, jak pokazano w poniższym przykładzie:
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;
}
}
Usuń wszystkie wpisy dla określonego tagu, wywołując funkcję RemoveByTagAsync z wartością tagu. Funkcja przeciążenia umożliwia określenie kolekcji wartości tagów.
Ani IMemoryCache ani IDistributedCache nie mają bezpośredniej obsługi koncepcji tagów, więc unieważnienie oparte na tagach jest tylko operacją logiczną. Nie usuwa aktywnie wartości z lokalnej lub rozproszonej pamięci podręcznej. Zamiast tego zapewnia, że podczas odbierania danych z takimi znacznikami, dane są traktowane jako nietrafione zarówno w lokalnej, jak i zdalnej pamięci podręcznej. Wartości wygasają dla IMemoryCache i IDistributedCache w zwykły sposób na podstawie skonfigurowanego czasu życia.
Usuwanie wszystkich wpisów w pamięci podręcznej
Tag asterisku (*) został zarezerwowany jako symbol wieloznaczny i jest niedozwolony w odniesieniu do poszczególnych wartości. Wywołanie RemoveByTagAsync("*") ma wpływ na unieważnienie wszystkichHybridCache danych, nawet danych, które nie mają żadnych tagów. Podobnie jak w przypadku poszczególnych tagów, jest to operacja logiczna , a poszczególne wartości nadal istnieją do momentu ich naturalnego wygaśnięcia. Dopasowania w stylu globu nie są obsługiwane. Na przykład nie można użyć RemoveByTagAsync("foo*"), aby usunąć wszystko, co zaczyna się od foo.
Dodatkowe zagadnienia dotyczące tagów
- System nie ogranicza liczby tagów, których można użyć, ale duże zestawy tagów mogą negatywnie wpłynąć na wydajność.
- Tagi nie mogą być puste, zawierać tylko białe znaki ani mieć zarezerwowanej wartości
*.
Opcje
Metody AddHybridCache można użyć do skonfigurowania wartości domyślnych globalnych. W poniższym przykładzie pokazano, jak skonfigurować niektóre z dostępnych opcji:
// 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 może również przyjąć obiekt HybridCacheEntryOptions w celu zmiany globalnych wartości domyślnych dla określonego wpisu pamięci podręcznej. Oto przykład:
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;
}
}
Aby uzyskać więcej informacji na temat opcji, zobacz kod źródłowy:
- Klasa HybridCacheOptions.
- Klasa HybridCacheEntryOptions.
Limity
Następujące właściwości HybridCacheOptions umożliwiają skonfigurowanie limitów, które mają zastosowanie do wszystkich wpisów pamięci podręcznej:
- MaximumPayloadBytes — maksymalny rozmiar wpisu w pamięci podręcznej. Wartość domyślna to 1 MB. Próby przechowywania wartości w tym rozmiarze są rejestrowane, a wartość nie jest przechowywana w pamięci podręcznej.
- MaximumKeyLength — maksymalna długość klucza pamięci podręcznej. Wartość domyślna to 1024 znaki. Próby przechowywania wartości w tym rozmiarze są rejestrowane, a wartość nie jest przechowywana w pamięci podręcznej.
Serializacja
Użycie pomocniczej pamięci podręcznej poza procesem wymaga serializacji. Konfiguracja serializacji jest częścią rejestrowania usługi HybridCache. Serializatory specyficzne dla typu i ogólnego przeznaczenia można skonfigurować za pomocą metod AddSerializer i AddSerializerFactory, łańcuchowo od wywołania AddHybridCache. Domyślnie biblioteka obsługuje string i byte[] wewnętrznie, a do wszystkiego innego używa System.Text.Json.
HybridCache może również używać innych serializatorów, takich jak protobuf lub XML.
Poniższy przykład konfiguruje usługę do użycia serializatora protobuf, który jest specyficzny dla danego typu:
// 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>>();
Poniższy przykład konfiguruje usługę tak, aby korzystała z serializatora protobuf ogólnego przeznaczenia, który może obsługiwać wiele typów 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>();
Pomocnicza pamięć podręczna wymaga magazynu danych, takiego jak Redis, SQL Server lub Postgres. Aby użyć usługi Azure Cache for Redis, na przykład:
Zainstaluj pakiet
Microsoft.Extensions.Caching.StackExchangeRedis.Utwórz instancję Azure Cache for Redis.
Uzyskaj ciąg połączenia, który łączy się z wystąpieniem Redis. Znajdź parametry połączenia, wybierając pozycję Pokaż klucze dostępu na stronie Przegląd w witrynie Azure Portal.
Zapisz parametry połączenia w konfiguracji aplikacji. Na przykład użyj pliku tajnych danych użytkownika, który wygląda podobnie do poniższego kodu JSON, z łańcuchem połączenia w sekcji
ConnectionStrings. Zastąp<the connection string>rzeczywistym ciągiem połączenia:{ "ConnectionStrings": { "RedisConnectionString": "<the connection string>" } }Zarejestruj w DI implementację
IDistributedCache, którą zapewnia pakiet Redis. Aby to zrobić, wywołaj metodęAddStackExchangeRedisCachei przekaż parametry połączenia. Na przykład:builder.Services.AddStackExchangeRedisCache(options => { options.Configuration = builder.Configuration.GetConnectionString("RedisConnectionString"); });Implementacja usługi Redis
IDistributedCachejest teraz dostępna z kontenera DI aplikacji.HybridCacheużywa go jako pomocniczej pamięci podręcznej i używa serializatora skonfigurowanego dla niego.
Aby uzyskać więcej informacji, zobacz przykładową aplikację serializacji HybridCache.
Pamięć podręczna
Domyślnie HybridCache używa MemoryCache dla swojego podstawowego magazynu pamięci podręcznej. Wpisy pamięci podręcznej są przechowywane w procesie, dlatego każdy serwer ma oddzielną pamięć podręczną, która zostanie utracona przy każdym ponownym uruchomieniu procesu serwera. W przypadku wtórnej pamięci poza procesem, takiej jak Redis, SQL Server lub Postgres, HybridCache używa skonfigurowanej IDistributedCache implementacji, jeśli jest. Ale nawet bez implementacji IDistributedCacheusługa HybridCache nadal zapewnia buforowanie procesowe i ochronę przed przeciążeniami.
Notatka
Podczas unieważniania wpisów pamięci podręcznej według klucza lub tagów, są one unieważniane zarówno na bieżącym serwerze, jak i w zewnętrznej pamięci poza procesem. Jednak nie ma to wpływu na pamięć podręczną na innych serwerach.
Optymalizowanie wydajności
Aby zoptymalizować wydajność, skonfiguruj HybridCache do ponownego użycia obiektów oraz unikaj alokacji byte[].
Ponowne używanie obiektów
Przez ponowne użycie wystąpień, HybridCache może zmniejszyć obciążenie związane z alokacją obiektów przy każdym wywołaniu deserializacji. Może to prowadzić do poprawy wydajności w scenariuszach, w których buforowane obiekty są duże lub często używane.
W typowym istniejącym kodzie, który używa IDistributedCache, każde pobieranie obiektu z pamięci podręcznej powoduje deserializację. To zachowanie oznacza, że każdy współbieżny wywołujący otrzymuje oddzielną instancję obiektu, która nie może współdziałać z innymi instancjami. Rezultatem jest bezpieczeństwo wielowątkowe, ponieważ nie ma ryzyka jednoczesnych modyfikacji tej samej instancji obiektu.
Ponieważ wiele HybridCache użycia zostanie dostosowanych z istniejącego IDistributedCache kodu, HybridCache domyślnie zachowuje to działanie, aby uniknąć wprowadzania usterek współbieżności. Jednak obiekty są z natury bezpieczne wątkowo, jeśli:
- Są to niezmienne typy.
- Kod ich nie modyfikuje.
W takich przypadkach należy poinformować HybridCache , że można bezpiecznie ponownie użyć wystąpień, wprowadzając oba następujące zmiany:
- Oznaczanie typu jako
sealed. Słowosealedkluczowe w języku C# oznacza, że nie można dziedziczyć klasy. - Stosowanie atrybutu
[ImmutableObject(true)]do typu. Atrybut[ImmutableObject(true)]wskazuje, że nie można zmienić stanu obiektu po jego utworzeniu.
Unikaj dokonywania byte[] alokacji
HybridCache udostępnia również opcjonalne interfejsy API w implementacjach IDistributedCache, aby uniknąć alokacji byte[]. Ta funkcja jest implementowana przez wersje zapoznawcze pakietów Microsoft.Extensions.Caching.StackExchangeRedis, Microsoft.Extensions.Caching.SqlServer i Microsoft.Extensions.Caching.Postgres. Aby uzyskać więcej informacji, zobacz IBufferDistributedCache.
Poniżej przedstawiono polecenia interfejsu wiersza polecenia platformy .NET służące do instalowania pakietów:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
dotnet add package Microsoft.Extensions.Caching.SqlServer
dotnet add package Microsoft.Extensions.Caching.Postgres
Niestandardowe implementacje usługi HybridCache
Konkretna implementacja klasy abstrakcyjnej HybridCache jest zawarta w strukturze udostępnionej i jest dostarczana za pośrednictwem wstrzykiwania zależności. Deweloperzy mogą z przyjemnością dostarczać lub korzystać z niestandardowych implementacji interfejsu API, na przykład FusionCache.
Używanie hybrydowej pamięci podręcznej z natywną funkcją AOT
Następujące zagadnienia specyficzne dla natywnej funkcji AOT mają zastosowanie do:HybridCache
Serializacja
Natywny AOT nie obsługuje serializacji opartej na odbiciu w czasie wykonywania. W przypadku buforowania typów niestandardowych należy użyć generatorów kodu źródłowego lub jawnie skonfigurować serializatory zgodne z AOT, takie jak generowanie źródła
System.Text.Json.HybridCachejest nadal w fazie rozwoju, a uproszczenie sposobu korzystania z niej z usługą AOT jest priorytetem w tym procesie rozwoju. Aby uzyskać więcej informacji, zobacz pull request dotnet/extensions#6475Przycinanie
Upewnij się, że wszystkie typy, które buforujesz, są przywoływane w sposób, który zapobiega ich przycinaniu przez kompilator AOT. Użycie generatorów źródłowych do serializacji pomaga w tym wymaganiu. Aby uzyskać więcej informacji, zobacz ASP.NET Core support for Native AOT (Obsługa natywnej funkcji AOT w systemie ASP.NET Core).
Jeśli prawidłowo skonfigurujesz serializację i przycinanie, HybridCache będzie działać tak samo w aplikacjach natywnych AOT, jak w zwykłych aplikacjach ASP.NET Core.
Zgodność
Biblioteka HybridCache obsługuje dawne środowiska uruchomieniowe platformy .NET, począwszy od wersji .NET Framework 4.7.2 i .NET Standard 2.0.
Dodatkowe zasoby
Aby uzyskać więcej informacji, zobacz HybridCache kod źródłowy