Model Doplňování mezipamětiCache-Aside pattern

Na vyžádání načte data z úložiště dat do mezipaměti.Load data on demand into a cache from a data store. To může zlepšit výkon a také pomoct se zachováním konzistence mezi daty drženými v mezipaměti a daty v základním úložišti.This can improve performance and also helps to maintain consistency between data held in the cache and data in the underlying data store.

Kontext a problémContext and problem

Aplikace využívají mezipaměť ke zlepšení opakovaného přístupu k informacím uloženým v datovém úložišti.Applications use a cache to improve repeated access to information held in a data store. Není však vhodné očekávat, že data uložená v mezipaměti budou vždy zcela konzistentní s daty v úložišti.However, it's impractical to expect that cached data will always be completely consistent with the data in the data store. Aplikace by měla mít implementovanou strategii, která pomáhá zajistit, aby data v mezipaměti byla co nejaktuálnější, ale která taky může rozpoznávat a řešit situace, které vznikají, když jsou data v mezipaměti zastaralá.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.

ŘešeníSolution

Řada komerčních systémů pro ukládání do mezipaměti umožňuje operace přímého čtení a přímého zápisu / opožděného zápisu.Many commercial caching systems provide read-through and write-through/write-behind operations. V těchto systémech aplikace načte data odkazováním na mezipaměť.In these systems, an application retrieves data by referencing the cache. Pokud data v mezipaměti nejsou, načtou se z úložiště dat a přidají se do mezipaměti.If the data isn't in the cache, it's retrieved from the data store and added to the cache. Všechny úpravy dat v mezipaměti se automaticky zapíší zpět do úložiště dat.Any modifications to data held in the cache are automatically written back to the data store as well.

V případě mezipamětí, které tuto funkci nemají, jsou za správu dat zodpovědné aplikace, které mezipaměť používají.For caches that don't provide this functionality, it's the responsibility of the applications that use the cache to maintain the data.

Aplikace můžou emulovat funkci přímého čtení z mezipaměti implementací strategie doplňování mezipaměti.An application can emulate the functionality of read-through caching by implementing the cache-aside strategy. Tato strategie načte data do mezipaměti na vyžádání.This strategy loads data into the cache on demand. Obrázek znázorňuje ukládání dat do mezipaměti pomocí modelu Doplňování mezipaměti.The figure illustrates using the Cache-Aside pattern to store data in the cache.

Ukládání dat do mezipaměti pomocí modelu Doplňování mezipaměti

Pokud aplikace aktualizuje informace, může postupovat podle strategie přímého zápisu tím, že provede změnu v úložišti dat a zneplatní odpovídající položku v mezipaměti.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.

Jakmile bude položka příště vyžadovaná, použití strategie doplňování mezipaměti způsobí načtení aktualizovaných dat z úložiště dat a jejich přidání zpět do mezipaměti.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.

Problémy a důležité informaceIssues and considerations

Když se budete rozhodovat, jak tento model implementovat, měli byste vzít v úvahu následující skutečnosti:Consider the following points when deciding how to implement this pattern:

Doba platnosti dat uložených v mezipaměti.Lifetime of cached data. Řada mezipamětí má implementovanou zásadu vypršení platnosti, která zneplatní data a odstraní je z mezipaměti, pokud k nim po zadanou dobu neproběhne žádný přístup.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 bylo doplňování mezipaměti účinné, zajistěte, že zásada vypršení platnosti odpovídá modelu přístupu aplikací, které data používají.For cache-aside to be effective, ensure that the expiration policy matches the pattern of access for applications that use the data. Nenastavujte dobu vypršení platnosti příliš krátkou, protože by to mohlo mít za následek to, že aplikace budou průběžně načítat data z úložiště dat a přidávat je do mezipaměti.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. Stejně tak nenastavujte dobu vypršení platnosti tak dlouhou, aby se data uložená v mezipaměti stala zastaralými.Similarly, don't make the expiration period so long that the cached data is likely to become stale. Mějte na paměti, že ukládání do mezipaměti je nejúčinnější pro relativně statická data nebo data, která jsou často načítaná.Remember that caching is most effective for relatively static data, or data that is read frequently.

Vyřazení dat.Evicting data. Většina mezipaměti má v porovnání s úložištěm dat, odkud data pochází, omezenou velikost a v případě potřeby data vyřadí.Most caches have a limited size compared to the data store where the data originates, and they'll evict data if necessary. Většina mezipamětí používá k výběru dat k vyřazení zásadu nejméně používaných dat v poslední době, ale tato zásada může být přizpůsobitelná.Most caches adopt a least-recently-used policy for selecting items to evict, but this might be customizable. Abyste zajistili, že mezipaměť bude z hlediska nákladů efektivní, nakonfigurujte u mezipaměti globální vlastnost vypršení platnosti a další vlastnosti a u každé položky uložené v mezipaměti vlastnost vypršení platnosti.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. Není vždy vhodné použít globální zásadu vyřazení pro každou položku v mezipaměti.It isn't always appropriate to apply a global eviction policy to every item in the cache. Například pokud je položku v mezipaměti drahé načíst z úložiště dat, může být výhodné ponechat ji v mezipaměti na úkor častěji načítaných, ale levnějších položek.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.

Příprava mezipaměti.Priming the cache. Mnoho řešení předvyplní mezipaměť daty, které aplikace bude pravděpodobně potřebovat jako součást počátečního zpracování.Many solutions prepopulate the cache with the data that an application is likely to need as part of the startup processing. Doplňování mezipaměti může být přesto užitečné, pokud u některých z těchto dat vyprší platnost nebo dojde k jejich vyřazení.The Cache-Aside pattern can still be useful if some of this data expires or is evicted.

Konzistence.Consistency. Implementace modulu Doplňování mezipaměti nezaručuje konzistenci mezi úložištěm dat a mezipamětí.Implementing the Cache-Aside pattern doesn't guarantee consistency between the data store and the cache. Položky v úložišti dat může kdykoli změnit externí proces a tato změna se může v mezipaměti projevit až při příštím načtení položky.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. V systému, který replikuje data mezi úložišti dat, se může jednat o vážný problém, pokud k synchronizaci dochází často.In a system that replicates data across data stores, this problem can become serious if synchronization occurs frequently.

Místní ukládání do mezipaměti (v paměti).Local (in-memory) caching. Mezipaměť může být pro instanci aplikace místní a uložená v paměti.A cache could be local to an application instance and stored in-memory. V tomto prostředí může být model Doplňování mezipaměti užitečný, pokud aplikace opakovaně přistupuje ke stejným datům.Cache-aside can be useful in this environment if an application repeatedly accesses the same data. Místní mezipaměť je však soukromá, takže různé instance aplikace můžou mít kopii stejných dat uložených v mezipaměti.However, a local cache is private and so different application instances could each have a copy of the same cached data. Tato data můžou být zanedlouho mezi jednotlivými mezipamětmi nekonzistentní, takže pravděpodobně bude nutné častěji nechat vypršet platnost dat v soukromé mezipaměti a obnovovat je.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. V těchto scénářích zvažte použití sdíleného nebo distribuovaného mechanismu ukládání do mezipaměti.In these scenarios, consider investigating the use of a shared or a distributed caching mechanism.

Kdy se má tento model použítWhen to use this pattern

Tento model použijte v těchto případech:Use this pattern when:

  • Mezipaměť neposkytuje nativní operace přímého čtení a zápisu.A cache doesn't provide native read-through and write-through operations.
  • Požadavky na prostředky jsou nepředvídatelné.Resource demand is unpredictable. Tento model umožňuje aplikacím načítat data na vyžádání.This pattern enables applications to load data on demand. Model nepředpokládá, která data bude aplikace potřebovat předem.It makes no assumptions about which data an application will require in advance.

Tento model nebude pravděpodobně vhodný v následujících případech:This pattern might not be suitable:

  • Sada dat v mezipaměti je statická.When the cached data set is static. Pokud se data vejdou do dostupného prostoru v mezipaměti, naplňte mezipaměť daty při spuštění a použijte zásadu, která zabrání vypršení platnosti dat.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.
  • Pro ukládání informací o stavu relace do mezipaměti ve webové aplikaci hostovaná ve webové farmě.For caching session state information in a web application hosted in a web farm. V tomto prostředí byste se měli vyhnout vzniku závislostí podle vztahu klient-server.In this environment, you should avoid introducing dependencies based on client-server affinity.

PříkladExample

V Microsoft Azure můžete pomocí Azure Cache for Redis vytvořit distribuovanou mezipaměť, kterou může sdílet více instancí aplikace.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.

Následující příklady kódu používají klienta StackExchange.Redis, což je klientská knihovna Redis napsaná pro rozhraní .NET.This following code examples use the StackExchange.Redis client, which is a Redis client library written for .NET. Chcete-li se připojit k instanci ConnectionMultiplexer.Connect Azure Cache for Redis, zavolejte statickou metodu a předejte v připojovacím řetězci.To connect to an Azure Cache for Redis instance, call the static ConnectionMultiplexer.Connect method and pass in the connection string. Metoda vrátí ConnectionMultiplexer představující připojení.The method returns a ConnectionMultiplexer that represents the connection. Jeden ze způsobů sdílení instance ConnectionMultiplexer v aplikaci je pomocí statické vlastnosti, která vrací připojenou instanci, podobně jako v následujícím příkladu. 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. Tento přístup poskytuje způsob inicializace jedné připojené instance, který je bezpečný pro přístup z více vláken.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;

Metoda GetMyEntityAsync v následujícím příkladu kódu ukazuje implementaci vzoru Cache-Aside.The GetMyEntityAsync method in the following code example shows an implementation of the Cache-Aside pattern. Tato metoda načte objekt z mezipaměti pomocí přístupu pro čtení.This method retrieves an object from the cache using the read-through approach.

Objekt je identifikovaný pomocí celočíselného ID, který se použije jako klíč.An object is identified by using an integer ID as the key. Metoda GetMyEntityAsync se pokusí načíst položku s tímto klíčem z mezipaměti.The GetMyEntityAsync method tries to retrieve an item with this key from the cache. Pokud je nalezena odpovídající položka, načte se.If a matching item is found, it's returned. Pokud v mezipaměti není nalezena žádná shoda, metoda GetMyEntityAsync načte objekt z úložiště dat, přidá jej do mezipaměti a pak jej vrátí.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. Kód, který načítá data z úložiště dat, tady není ukázaný, protože se liší podle úložiště.The code that actually reads the data from the data store is not shown here, because it depends on the data store. Mějte na paměti, že položka uložená v mezipaměti má nakonfigurované vypršení platnosti, aby se v případě, že bude někde jinde aktualizována, nestala zastaralou.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;
}

Příklady používají Azure Cache pro Redis pro přístup k úložišti a načtení informací z mezipaměti.The examples use Azure Cache for Redis to access the store and retrieve information from the cache. Další informace najdete v tématu Použití azure cache pro Redis a jak vytvořit webovou aplikaci s Azure Cache pro Redis.For more information, see Using Azure Cache for Redis and How to create a Web App with Azure Cache for Redis.

Metoda UpdateEntityAsync níže ukazuje, jak zneplatnit objekt v mezipaměti, když aplikace změní jeho hodnotu.The UpdateEntityAsync method shown below demonstrates how to invalidate an object in the cache when the value is changed by the application. Kód aktualizuje původní úložiště dat a pak z mezipaměti odebere položku v ní uloženou.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.
}

Poznámka

Pořadí kroků je důležité.The order of the steps is important. Aktualizujte úložiště dat předtím, než položku odeberete z mezipaměti.Update the data store before removing the item from the cache. Pokud nejprve odeberte položku z mezipaměti, vznikne krátké časové okno, kdy klient může načíst položku předtím, než se aktualizuje úložiště dat.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. Výsledkem bude neúspěšný přístup do mezipaměti (protože položka byla z mezipaměti odstraněna), který způsobí, že se z úložiště dat načte starší verze položky a přidá se zpátky do mezipaměti.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. Výsledkem budou zastaralá data v mezipaměti.The result will be stale cache data.

Při implementaci tohoto modelu můžou být důležité tyto informace:The following information may be relevant when implementing this pattern:

  • Pokyny pro ukládání do mezipaměti.Caching Guidance. Obsahují další informace o tom, jak můžete v cloudovém řešení ukládat data do mezipaměti a o problémech, které byste měli při implementaci mezipaměti zvážit.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.

  • Základní nátěr konzistence dat.Data Consistency Primer. Cloudové aplikace obvykle používají data, která se nacházejí ve více úložištích dat.Cloud applications typically use data that's spread across data stores. Správa a údržba konzistence dat v takovém prostředí je nesmírně důležitý aspekt systému, zejména problémy souběžnosti a dostupnosti, které můžou nastat.Managing and maintaining data consistency in this environment is a critical aspect of the system, particularly the concurrency and availability issues that can arise. Tento úvod popisuje problémy s konzistencí napříč distribuovanými daty a shrnuje, jak aplikace může implementovat případnou konzistenci a zachovat dostupnost dat.This primer describes issues about consistency across distributed data, and summarizes how an application can implement eventual consistency to maintain the availability of data.