Wzorzec z odkładaniem do pamięci podręcznejCache-Aside pattern

Załaduj dane na żądanie do pamięci podręcznej z magazynu danych.Load data on demand into a cache from a data store. 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.This can improve performance and also helps to maintain consistency between data held in the cache and data in the underlying data store.

Kontekst i problemContext and problem

Aplikacje używają pamięci podręcznej, aby poprawić powtarzalny dostęp do informacji przechowywanych w magazynie danych.Applications use a cache to improve repeated access to information held in a data store. Jednak niepraktycznie jest oczekiwać, że dane w pamięci podręcznej będą zawsze całkowicie spójne z danymi w magazynie danych.However, it's impractical to expect that cached data will always be completely consistent with the data in the data store. Aplikacje powinny implementować strategię, dzięki której będą upewniać się, że dane w pamięci podręcznej są możliwie aktualne, ale mogą też wykrywać i obsługiwać sytuacje, w których dane w pamięci podręcznej są przestarzałe.Applications should implement a strategy that helps to ensure that the data in the cache is as up-to-date as possible, but can also detect and handle situations that arise when the data in the cache has become stale.

RozwiązanieSolution

Wiele komercyjnych systemów buforowania zapewnia operacje odczytu read-through oraz zapisu write-through/write-behind.Many commercial caching systems provide read-through and write-through/write-behind operations. W tych systemach aplikacja pobiera dane poprzez odwołanie do pamięci podręcznej.In these systems, an application retrieves data by referencing the cache. Jeśli dane nie znajdują się w pamięci podręcznej, zostaną pobrane z magazynu danych i dodane do pamięci podręcznej.If the data isn't in the cache, it's retrieved from the data store and added to the cache. Również wszelkie modyfikacje danych przechowywanych w pamięci podręcznej są automatycznie zapisywane z powrotem do magazynu danych.Any modifications to data held in the cache are automatically written back to the data store as well.

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.For caches that don't provide this functionality, it's the responsibility of the applications that use the cache to maintain the data.

Aplikacja może emulować funkcję buforowania read-through poprzez wdrożenie strategii odkładania do pamięci podręcznej.An application can emulate the functionality of read-through caching by implementing the cache-aside strategy. Ta strategia ładuje dane do pamięci podręcznej na żądanie.This strategy loads data into the cache on demand. Na rysunku przedstawiono użycie wzorca z odkładaniem do pamięci podręcznej w celu przechowywania danych w pamięci podręcznej.The figure illustrates using the Cache-Aside pattern to store data in the cache.

Użycie wzorca z odkładaniem do pamięci podręcznej w celu przechowywania danych w pamięci podręcznej

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.If an application updates information, it can follow the write-through strategy by making the modification to the data store, and by invalidating the corresponding item in the cache.

Jeśli element będzie później wymagany, użycie strategi z odkładaniem do pamięci podręcznej spowoduje pobranie zaktualizowanych danych z magazynu danych i ponowne ich dodanie do pamięci podręcznej.When the item is next required, using the cache-aside strategy will cause the updated data to be retrieved from the data store and added back into the cache.

Problemy i kwestie do rozważeniaIssues and considerations

Podczas podejmowania decyzji o sposobie wdrożenia tego wzorca należy rozważyć następujące punkty:Consider the following points when deciding how to implement this pattern:

Okres istnienia danych w pamięci podręcznej.Lifetime of cached data. Wiele pamięci podręcznych implementuje zasady wygasania, które unieważniają dane i usuwają je z pamięci podręcznej, jeśli nie uzyska się do nich dostępu w określonym przedziale czasowym.Many caches implement an expiration policy that invalidates data and removes it from the cache if it's not accessed for a specified period. 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.For cache-aside to be effective, ensure that the expiration policy matches the pattern of access for applications that use the data. Nie należy ustawiać zbyt krótkiego czasu wygasania, ponieważ może to doprowadzić do sytuacji, w której aplikacje będą ciągle pobierać dane z magazynu danych i dodawać je do pamięci podręcznej.Don't make the expiration period too short because this can cause applications to continually retrieve data from the data store and add it to the cache. Podobnie nie należy ustawiać zbyt długiego czasu wygasania — wtedy dane w pamięci podręcznej prawdopodobnie będą przestarzałe.Similarly, don't make the expiration period so long that the cached data is likely to become stale. Należy pamiętać, że buforowanie jest najbardziej efektywne wobec względnie statycznych danych lub danych, które są często odczytywane.Remember that caching is most effective for relatively static data, or data that is read frequently.

Eksmisja danych.Evicting data. Większość pamięci podręcznych ma ograniczony rozmiar w porównaniu do magazynu danych zawierającego oryginalne dane i będzie eksmitować dane w razie potrzeby.Most caches have a limited size compared to the data store where the data originates, and they'll evict data if necessary. Większość pamięci podręcznych stosuje zasady najdawniej używanych w przypadku elementów do eksmitowania, ale można to zmienić.Most caches adopt a least-recently-used policy for selecting items to evict, but this might be customizable. Skonfiguruj globalne właściwości wygasania oraz inne właściwości pamięci podręcznej, a także właściwości wygasania wszystkich elementów pamięci podręcznej, aby upewnić się, że pamięć podręczna jest ekonomiczna.Configure the global expiration property and other properties of the cache, and the expiration property of each cached item, to ensure that the cache is cost effective. Nie zawsze stosowanie globalnych zasad eksmisji wobec każdego elementu w pamięci podręcznej jest odpowiednie.It isn't always appropriate to apply a global eviction policy to every item in the cache. Na przykład jeśli element pamięci podręcznej jest bardzo kosztowny w przypadku pobierania z magazynu danych, korzystne może być przechowywanie tego elementu w pamięci podręcznej kosztem elementów, do których dostęp uzyskuje się częściej, ale też które są mniej kosztowne.For example, if a cached item is very expensive to retrieve from the data store, it can be beneficial to keep this item in the cache at the expense of more frequently accessed but less costly items.

Zalewanie pamięci podręcznej.Priming the cache. 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.Many solutions prepopulate the cache with the data that an application is likely to need as part of the startup processing. 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.The Cache-Aside pattern can still be useful if some of this data expires or is evicted.

Spójność.Consistency. Implementacja wzorca z odkładaniem do pamięci podręcznej nie gwarantuje spójności między magazynem danych i pamięcią podręczną.Implementing the Cache-Aside pattern doesn't guarantee consistency between the data store and the cache. Element w magazynie danych może zostać zmieniony w dowolnym momencie przez proces zewnętrzny, a ta zmiana może nie zostać uwzględniona w pamięci podręcznej do następnego załadowania elementu.An item in the data store can be changed at any time by an external process, and this change might not be reflected in the cache until the next time the item is loaded. W systemie replikującym dane w magazynach danych ten problem może być poważny, jeśli synchronizacja występuje często.In a system that replicates data across data stores, this problem can become serious if synchronization occurs frequently.

Buforowanie lokalne (w pamięci).Local (in-memory) caching. Pamięć podręczna może być lokalna dla wystąpienia aplikacji i przechowywana w pamięci.A cache could be local to an application instance and stored in-memory. 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.Cache-aside can be useful in this environment if an application repeatedly accesses the same data. 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.However, a local cache is private and so different application instances could each have a copy of the same cached data. 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.This data could quickly become inconsistent between caches, so it might be necessary to expire data held in a private cache and refresh it more frequently. W tych scenariuszach należy rozważyć zbadanie użycia udostępnionego lub rozproszonego mechanizmu buforowania.In these scenarios, consider investigating the use of a shared or a distributed caching mechanism.

Kiedy używać tego wzorcaWhen to use this pattern

Użyj tego wzorca, gdy:Use this pattern when:

  • Pamięć podręczna nie zapewnia natywnych operacji read-through i write-through.A cache doesn't provide native read-through and write-through operations.
  • Żądanie zasobu jest nieprzewidywalne.Resource demand is unpredictable. Ten wzorzec umożliwia aplikacjom ładowanie danych na żądanie.This pattern enables applications to load data on demand. Nie tworzy z wyprzedzeniem założeń dotyczących danych, których aplikacje będą potrzebować.It makes no assumptions about which data an application will require in advance.

Ten wzorzec może nie być przydatny w następujących sytuacjach:This pattern might not be suitable:

  • Gdy zestaw danych w pamięci podręcznej jest statyczny.When the cached data set is static. Jeśli dane zmieszczą się w dostępnej przestrzeni pamięci podręcznej, wypełnij pamięć podręczną danymi podczas uruchamiania i zastosuj zasady, które ochroną dane przed wygaśnięciem.If the data will fit into the available cache space, prime the cache with the data on startup and apply a policy that prevents the data from expiring.
  • W przypadku buforowania informacji o stanie sesji w aplikacji internetowej hostowanej na farmie internetowej.For caching session state information in a web application hosted in a web farm. W tym środowisku należy unikać wprowadzania zależności opartych na koligacji klient-serwer.In this environment, you should avoid introducing dependencies based on client-server affinity.

PrzykładExample

W Microsoft Azure można użyć usługi Azure cache for Redis do utworzenia rozproszonej pamięci podręcznej, która może być współużytkowana przez wiele wystąpień aplikacji.In Microsoft Azure you can use Azure Cache for Redis to create a distributed cache that can be shared by multiple instances of an application.

W poniższym przykładzie kodu użyto klienta stackexchange. Redis , który jest biblioteką klienta Redis zapisaną dla platformy .NET.This following code examples use the StackExchange.Redis client, which is a Redis client library written for .NET. Aby nawiązać połączenie z usługą Azure cache for Redis, wywołaj ConnectionMultiplexer.Connect metodę statyczną i przekaż parametry połączenia.To connect to an Azure Cache for Redis instance, call the static ConnectionMultiplexer.Connect method and pass in the connection string. Metoda zwraca klasę ConnectionMultiplexer reprezentującą połączenie.The method returns a ConnectionMultiplexer that represents the connection. 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.One approach to sharing a ConnectionMultiplexer instance in your application is to have a static property that returns a connected instance, similar to the following example. To podejście oferuje bezpieczny wątkowo sposób na inicjowanie tylko jednego połączonego wystąpienia.This approach provides a thread-safe way to initialize only a single connected instance.

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;

GetMyEntityAsyncMetoda w poniższym przykładzie kodu przedstawia implementację wzorca Cache-Aside.The GetMyEntityAsync method in the following code example shows an implementation of the Cache-Aside pattern. Ta metoda pobiera obiekt z pamięci podręcznej przy użyciu metody read-through.This method retrieves an object from the cache using the read-through approach.

Obiekt jest identyfikowany przy użyciu identyfikatora w formie liczby całkowitej jako klucza.An object is identified by using an integer ID as the key. Metoda GetMyEntityAsync próbuje pobrać element z tym kluczem z pamięci podręcznej.The GetMyEntityAsync method tries to retrieve an item with this key from the cache. Jeśli zostanie znaleziony pasujący element, zostanie on zwrócony.If a matching item is found, it's returned. 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.If there's no match in the cache, the GetMyEntityAsync method retrieves the object from a data store, adds it to the cache, and then returns it. Kod, który faktycznie odczytuje dane z magazynu danych, nie został tutaj pokazany, ponieważ jest zależny od magazynu danych.The code that actually reads the data from the data store is not shown here, because it depends on the data store. Należy pamiętać, że element pamięci podręcznej jest skonfigurowany na wygaśnięcie, aby zapobiegać sytuacji, w której będzie przestarzały, jeśli zostanie zaktualizowany w innym miejscu.Note that the cached item is configured to expire to prevent it from becoming stale if it's updated elsewhere.

// 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;
}

Przykłady używają usługi Azure cache for Redis, aby uzyskać dostęp do magazynu i pobrać informacje z pamięci podręcznej.The examples use Azure Cache for Redis to access the store and retrieve information from the cache. Aby uzyskać więcej informacji, zobacz Korzystanie z usługi Azure cache for Redis oraz Tworzenie aplikacji sieci Web za pomocą usługi Azure cache for Redis.For more information, see Using Azure Cache for Redis and How to create a Web App with Azure Cache for Redis.

Metoda UpdateEntityAsync przedstawiona poniżej demonstruje sposób unieważniania obiektu w pamięci podręcznej, kiedy wartość zostanie zmieniona przez aplikację.The UpdateEntityAsync method shown below demonstrates how to invalidate an object in the cache when the value is changed by the application. Kod aktualizuje oryginalny magazyn danych, a następnie usuwa element pamięci podręcznej z pamięci podręcznej.The code updates the original data store and then removes the cached item from the cache.

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.The order of the steps is important. Zaktualizuj magazyn danych przed usunięciem elementu z pamięci podręcznej.Update the data store before removing the item from the cache. Jeśli najpierw usuniesz element pamięci podręcznej, zaistnieje niewielki przedział czasu, w którym klient może pobrać element przed zaktualizowaniem magazynu danych.If you remove the cached item first, there is a small window of time when a client might fetch the item before the data store is updated. Spowoduje to chybienie pamięci podręcznej (ponieważ element został usunięty z pamięci podręcznej), co z kolei doprowadzi do pobrania wcześniejszej wersji elementu z magazynu danych i dodania jej z powrotem do pamięci podręcznej.That will result in a cache miss (because the item was removed from the cache), causing the earlier version of the item to be fetched from the data store and added back into the cache. W rezultacie otrzymamy przestarzałe dane w pamięci podręcznej.The result will be stale cache data.

Następujące informacje mogą być istotne w przypadku implementowania tego wzorca:The following information may be relevant when implementing this pattern:

  • Wskazówki dotyczące buforowania.Caching Guidance. 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.Provides additional information on how you can cache data in a cloud solution, and the issues that you should consider when you implement a cache.

  • Podstawowe dane.Data Consistency Primer. Aplikacje w chmurze zazwyczaj używają danych rozproszonych w różnych magazynach danych.Cloud applications typically use data that's spread across data stores. Zarządzanie spójnością danych i jej utrzymywanie w tym środowisku jest krytycznym aspektem systemu, zwłaszcza w obliczu problemów z współbieżnością i dostępnością, które mogą wystąpić.Managing and maintaining data consistency in this environment is a critical aspect of the system, particularly the concurrency and availability issues that can arise. 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.This primer describes issues about consistency across distributed data, and summarizes how an application can implement eventual consistency to maintain the availability of data.