Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Załaduj dane na żądanie do pamięci podręcznej z magazynu danych. Może to poprawić wydajność oraz pomóc w utrzymaniu spójności między danymi w pamięci podręcznej i danymi w podstawowym magazynie danych.
Kontekst i problem
Aplikacje używają pamięci podręcznej, aby poprawić powtarzalny dostęp do informacji przechowywanych w magazynie danych. Jednak nierealne jest oczekiwanie, że buforowane dane będą zawsze zgodne z magazynem danych. Aplikacje powinny wdrożyć strategię, która pomaga zapewnić, że dane w pamięci podręcznej są tak up-to-date, jak to możliwe. Strategia powinna być również w stanie wykryć, kiedy buforowane dane staną się nieaktualne i odpowiednio je obsłużyć.
Rozwiązanie
Wiele komercyjnych systemów buforowania zapewnia operacje odczytu read-through oraz zapisu write-through/write-behind. W tych systemach aplikacja pobiera dane poprzez odwołanie do pamięci podręcznej. Jeśli dane nie są w pamięci podręcznej, aplikacja pobiera je z magazynu danych i dodaje je do pamięci podręcznej. Również wszelkie modyfikacje danych przechowywanych w pamięci podręcznej są automatycznie zapisywane z powrotem do magazynu danych.
W przypadku pamięci podręcznych, które nie zapewniają tej funkcji, odpowiedzialność za utrzymanie danych spada na aplikacje używające pamięci podręcznej.
Aplikacja może emulować funkcję buforowania read-through poprzez wdrożenie strategii odkładania do pamięci podręcznej. Ta strategia ładuje dane do pamięci podręcznej na żądanie. Na rysunku przedstawiono użycie wzorca z odkładaniem do pamięci podręcznej w celu przechowywania danych w pamięci podręcznej.
- Aplikacja określa, czy element jest obecnie przechowywany w pamięci podręcznej, próbując odczytać z pamięci podręcznej.
- Jeśli element nie jest bieżący w pamięci podręcznej (brakuje pamięci podręcznej), aplikacja pobiera element z magazynu danych.
- Aplikacja dodaje element do pamięci podręcznej, a następnie zwraca go do obiektu wywołującego.
Jeśli aplikacja aktualizuje informacje, może stosować strategię zapisu write-through, wprowadzając modyfikację w magazynie danych oraz unieważniając odpowiadający element w pamięci podręcznej.
Gdy element będzie potrzebny ponownie, strategia odkładania do pamięci podręcznej pobiera zaktualizowane dane z magazynu danych i dodaje je do pamięci podręcznej.
Problemy i kwestie do rozważenia
Podczas podejmowania decyzji o sposobie wdrożenia tego wzorca należy rozważyć następujące punkty:
Okres istnienia danych w pamięci podręcznej. Wiele pamięci podręcznych używa zasad wygasania, aby unieważniać dane i usuwać je z pamięci podręcznej, jeśli nie są dostępne przez określony okres. Aby strategia z odkładaniem do pamięci podręcznej była efektywna, należy upewnić się, że zasady wygasania pasują do wzorca dostępu aplikacji używających danych. Nie należy zbyt krótki okres wygaśnięcia, ponieważ przedwczesne wygaśnięcie może spowodować, że aplikacje będą stale pobierać dane z magazynu danych i dodawać je do pamięci podręcznej. Podobnie nie należy ustawiać zbyt długiego czasu wygasania — wtedy dane w pamięci podręcznej prawdopodobnie będą przestarzałe. Należy pamiętać, że buforowanie jest najbardziej efektywne wobec względnie statycznych danych lub danych, które są często odczytywane.
Eksmisja danych. Większość pamięci podręcznych ma ograniczony rozmiar w porównaniu z magazynem danych, z którego pochodzą dane. Jeśli pamięć podręczna przekroczy limit rozmiaru, eksmituje dane. Większość pamięci podręcznych stosuje co najmniej ostatnio używane zasady wybierania elementów do eksmisji, ale może to być możliwe do dostosowania.
Konfiguracja. Konfigurację pamięci podręcznej można ustawić zarówno globalnie, jak i na element buforowany. Jedna globalna zasada eksmisji może nie odpowiadać wszystkim elementom. Konfiguracja elementu pamięci podręcznej może być odpowiednia, jeśli element jest kosztowny do pobrania. W takiej sytuacji warto zachować element w pamięci podręcznej, nawet jeśli dostęp do niego jest rzadziej używany niż tańsze elementy.
Zalewanie pamięci podręcznej. Wiele rozwiązań wstępnie wypełnia pamięć podręczną przy użyciu danych, których aplikacja prawdopodobnie będzie potrzebować w ramach przetwarzania uruchomienia aplikacji. Wzorzec odkładania do pamięci podręcznej może nadal być użyteczny, jeśli niektóre z tych danych wygasną lub zostaną eksmitowane.
Spójność. Implementacja wzorca z odkładaniem do pamięci podręcznej nie gwarantuje spójności między magazynem danych i pamięcią podręczną. Na przykład proces zewnętrzny może w dowolnym momencie zmienić element w magazynie danych. Ta zmiana nie jest wyświetlana w pamięci podręcznej, dopóki element nie zostanie załadowany ponownie. W systemie, który replikuje dane w magazynach danych, spójność może być trudna, jeśli synchronizacja występuje często.
Buforowanie lokalne (w pamięci). Pamięć podręczna może być lokalna dla wystąpienia aplikacji i przechowywana w pamięci. Strategia odkładania do pamięci podręcznej może być użyteczna w tym środowisku, jeśli aplikacja wielokrotnie uzyskuje dostęp do tych samych danych. Jednak lokalna pamięć podręczna jest prywatna, więc różne wystąpienia aplikacji mogą mieć kopię tych samych danych w pamięci podręcznej. Te dane mogą szybko utracić spójność pomiędzy pamięciami podręcznymi, więc może być konieczne częstsze wygaszanie danych przechowywanych w prywatnej pamięci podręcznej i ich odświeżanie. W tych scenariuszach należy rozważyć zbadanie użycia udostępnionego lub rozproszonego mechanizmu buforowania.
Buforowanie semantyczne. Niektóre obciążenia mogą korzystać z pobierania pamięci podręcznej na podstawie semantycznego znaczenia, a nie dokładnych kluczy. Zmniejsza to liczbę żądań i tokenów wysyłanych do modeli językowych. Upewnij się, że buforowane dane wynikają z równoważności semantycznej i nie ryzykuje zwracania niepowiązanych odpowiedzi ani zawierają prywatnych i poufnych danych. Na przykład "Co to jest moja roczna pensja w domu?" jest semantycznie podobna do "Co to jest moja roczna płaca domowa?", ale jeśli zostanie zapytana przez dwóch różnych użytkowników, więc odpowiedź nie powinna być taka sama, ani nie chcesz uwzględniać tych poufnych danych w pamięci podręcznej.
Kiedy używać tego wzorca
Użyj tego wzorca, gdy:
- Pamięć podręczna nie zapewnia natywnych operacji read-through i write-through.
- Żądanie zasobu jest nieprzewidywalne. Ten wzorzec umożliwia aplikacjom ładowanie danych na żądanie. Nie przyjmuje żadnych założeń dotyczących danych, których aplikacja wymaga z wyprzedzeniem.
Ten wzorzec może nie być przydatny w następujących sytuacjach:
- Jeśli dane są poufne lub związane z zabezpieczeniami. Przechowywanie jej w pamięci podręcznej może być niewłaściwe, szczególnie jeśli pamięć podręczna jest współdzielona między wieloma aplikacjami lub użytkownikami. Zawsze przejdź do podstawowego źródła danych.
- Gdy zestaw danych w pamięci podręcznej jest statyczny. Jeśli dane mieszczą się w dostępnej przestrzeni pamięci podręcznej, należy zastosować zasady uniemożliwiające wygaśnięcie danych w pamięci podręcznej przy uruchamianiu.
- Gdy większość żądań nie napotka trafienia w pamięci podręcznej. W takiej sytuacji obciążenie związane z sprawdzaniem pamięci podręcznej i ładowaniem danych do niej może przewyższać korzyści wynikające z buforowania.
- Podczas buforowania informacji o stanie sesji w aplikacji internetowej hostowanej w farmie sieci Web. W tym środowisku należy unikać wprowadzania zależności opartych na koligacji klient-serwer.
Projekt obciążenia
Architekt powinien ocenić, w jaki sposób wzorzec Cache-Aside może być używany w projekcie w celu rozwiązania celów i zasad omówionych w filarach platformy Azure Well-Architected Framework. Na przykład:
| Filar | Jak ten wzorzec obsługuje cele filaru |
|---|---|
| Decyzje projektowe dotyczące niezawodności pomagają obciążeniu stać się odporne na awarię i zapewnić, że zostanie przywrócony do w pełni funkcjonalnego stanu po wystąpieniu awarii. | Buforowanie tworzy replikację danych i w ograniczony sposób może służyć do zachowania dostępności często używanych danych, jeśli magazyn danych pochodzenia jest tymczasowo niedostępny. Ponadto w przypadku awarii pamięci podręcznej obciążenie może wrócić do magazynu danych pochodzenia. - Nadmiarowość RE:05 |
| Wydajność pomagawydajnie sprostać zapotrzebowaniu dzięki optymalizacjom skalowania, danych, kodu. | Korzystanie z kabiny pamięci podręcznej zwiększa wydajność w przypadku danych o dużym obciążeniu odczytu, które zmieniają się rzadko i mogą tolerować pewne nieaktualności. - PE:08 Wydajność danych - PE:12 Ciągła optymalizacja wydajności |
Podobnie jak w przypadku każdej decyzji projektowej, należy rozważyć wszelkie kompromisy w stosunku do celów innych filarów, które mogą zostać wprowadzone przy użyciu tego wzorca.
Przykład
Rozważ użycie usługi Azure Managed Redis do utworzenia rozproszonej pamięci podręcznej, którą może współużytkować wiele wystąpień aplikacji.
W poniższym przykładzie kodu użyto klienta StackExchange.Redis, który jest biblioteką klienta Redis napisaną dla platformy .NET. Aby nawiązać połączenie z wystąpieniem usługi Azure Managed Redis, wywołaj metodę statyczną ConnectionMultiplexer.Connect i przekaż parametry połączenia. Metoda zwraca klasę ConnectionMultiplexer reprezentującą połączenie. Jednym z rozwiązań w zakresie udostępniania wystąpienia klasy ConnectionMultiplexer w aplikacji jest korzystanie z właściwości statycznej, która zwraca połączone wystąpienie podobnie jak w poniższym przykładzie. To podejście oferuje bezpieczny wątkowo sposób na inicjowanie tylko jednego połączonego wystąpienia.
private static ConnectionMultiplexer Connection;
// Redis connection string information
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
string cacheConnection = ConfigurationManager.AppSettings["CacheConnection"].ToString();
return ConnectionMultiplexer.Connect(cacheConnection);
});
public static ConnectionMultiplexer Connection => lazyConnection.Value;
Metoda GetMyEntityAsync w poniższym przykładzie kodu przedstawia implementację wzorca z odkładania do pamięci podręcznej. Ta metoda pobiera obiekt z pamięci podręcznej przy użyciu podejścia odczytu.
Obiekt jest identyfikowany przy użyciu identyfikatora w formie liczby całkowitej jako klucza. Metoda GetMyEntityAsync próbuje pobrać element z tym kluczem z pamięci podręcznej. Jeśli zostanie znaleziony pasujący element, pamięć podręczna zwróci go. Jeśli nie ma pasującego elementu w pamięci podręcznej, metoda GetMyEntityAsync pobierze obiekt z magazynu danych, doda go do pamięci podręcznej, a następnie go zwróci. Kod odczytujący dane z magazynu danych nie jest tutaj wyświetlany, ponieważ zależy od magazynu danych. Buforowany element jest skonfigurowany do wygaśnięcia, aby zapobiec jego nieaktualności, jeśli inna usługa lub proces go zaktualizuje.
// Set five minute expiration as a default
private const double DefaultExpirationTimeInMinutes = 5.0;
public async Task<MyEntity> GetMyEntityAsync(int id)
{
// Define a unique key for this method and its parameters.
var key = $"MyEntity:{id}";
var cache = Connection.GetDatabase();
// Try to get the entity from the cache.
var json = await cache.StringGetAsync(key).ConfigureAwait(false);
var value = string.IsNullOrWhiteSpace(json)
? default(MyEntity)
: JsonConvert.DeserializeObject<MyEntity>(json);
if (value == null) // Cache miss
{
// If there's a cache miss, get the entity from the original store and cache it.
// Code has been omitted because it is data store dependent.
value = ...;
// Avoid caching a null value.
if (value != null)
{
// Put the item in the cache with a custom expiration time that
// depends on how critical it is to have stale data.
await cache.StringSetAsync(key, JsonConvert.SerializeObject(value)).ConfigureAwait(false);
await cache.KeyExpireAsync(key, TimeSpan.FromMinutes(DefaultExpirationTimeInMinutes)).ConfigureAwait(false);
}
}
return value;
}
W przykładach użyto usługi Azure Managed Redis, aby uzyskać dostęp do magazynu i pobrać informacje z pamięci podręcznej. Aby uzyskać więcej informacji, zobacz Tworzenie usługi Azure Managed Redis i Używanie usługi Azure Redis na platformie .NET Core.
Metoda UpdateEntityAsync pokazana poniżej pokazuje, jak unieważnić obiekt w pamięci podręcznej, gdy aplikacja zmienia wartość. Kod aktualizuje oryginalny magazyn danych, a następnie usuwa element pamięci podręcznej z pamięci podręcznej.
public async Task UpdateEntityAsync(MyEntity entity)
{
// Update the object in the original data store.
await this.store.UpdateEntityAsync(entity).ConfigureAwait(false);
// Invalidate the current cache object.
var cache = Connection.GetDatabase();
var id = entity.Id;
var key = $"MyEntity:{id}"; // The key for the cached object.
await cache.KeyDeleteAsync(key).ConfigureAwait(false); // Delete this key from the cache.
}
Uwaga
Kolejność kroków jest ważna. Zaktualizuj magazyn danych przed usunięciem elementu z pamięci podręcznej. Jeśli najpierw usuniesz buforowany element, zostanie wyświetlone małe okno czasu, w którym klient może pobrać element przed zaktualizowaniem magazynu danych. W takiej sytuacji pobieranie powoduje pominięcie pamięci podręcznej (ponieważ element został usunięty z pamięci podręcznej). Chybienie pamięci podręcznej powoduje pobranie wcześniejszej wersji elementu z magazynu danych i dodanie jej z powrotem do pamięci podręcznej. Wynikiem są nieaktualne dane pamięci podręcznej.
Powiązane zasoby
Podczas implementowania tego wzorca mogą być istotne następujące informacje:
Wzorzec niezawodnej aplikacji internetowej pokazuje, jak zastosować wzorzec z odkładaniem do pamięci podręcznej do aplikacji internetowych zbieżnych w chmurze.
Wskazówki dotyczące buforowania. Zawierają dodatkowe informacje dotyczące sposobu buforowania danych w rozwiązaniu w chmurze oraz problemów, które należy rozważyć podczas implementowania pamięci podręcznej.
Podstawy spójności danych. Aplikacje w chmurze zwykle przechowują dane w wielu magazynach danych i lokalizacjach. Zarządzanie i utrzymywanie spójności danych w tym środowisku jest krytycznym aspektem systemu, szczególnie współbieżnością i problemami z dostępnością, które mogą wystąpić. Te podstawy opisują problemy związane ze spójnością rozproszonych danych oraz podsumowują sposób wdrażania spójności ostatecznej przez aplikację w celu zapewnienia dostępności danych.
Użyj usługi Azure Managed Redis jako semantycznej pamięci podręcznej. W tym samouczku pokazano, jak zaimplementować buforowanie semantyczne przy użyciu usługi Azure Managed Redis.