Modèle Cache-AsideCache-Aside pattern

Chargez les données à la demande dans un cache à partir d’une banque de données.Load data on demand into a cache from a data store. Cela peut améliorer les performances et aider à maintenir la cohérence entre les données contenues dans le cache et les données résidant dans la banque de données sous-jacente.This can improve performance and also helps to maintain consistency between data held in the cache and data in the underlying data store.

Contexte et problèmeContext and problem

Les applications utilisent un cache pour optimiser l’accès répété aux informations contenues dans une banque de données.Applications use a cache to improve repeated access to information held in a data store. Toutefois, on peut difficilement s’attendre à ce que les données mises en cache soient toujours entièrement cohérentes avec les données contenues dans la banque de données.However, it's impractical to expect that cached data will always be completely consistent with the data in the data store. Les applications doivent implémenter une stratégie pour s’assurer que les données contenues dans le cache soient le plus à jour possible, mais également pour identifier et gérer les situations dans lesquelles les données du cache sont devenues obsolètes.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.

SolutionSolution

De nombreux systèmes de mise en cache disponibles sur le marché intègrent des opérations de double lecture et de double écriture/d’écriture différée.Many commercial caching systems provide read-through and write-through/write-behind operations. Dans ces systèmes, une application récupère des données en établissant une référence au cache.In these systems, an application retrieves data by referencing the cache. Si les données ne se trouvent pas dans le cache, elles sont récupérées dans la banque de données et ajoutées au cache.If the data isn't in the cache, it's retrieved from the data store and added to the cache. Les modifications apportées aux données contenues dans le cache sont automatiquement répercutées dans la banque de données.Any modifications to data held in the cache are automatically written back to the data store as well.

Pour les caches qui n’offrent pas cette fonctionnalité, il revient aux applications qui utilisent le cache d’assurer la mise à jour des données.For caches that don't provide this functionality, it's the responsibility of the applications that use the cache to maintain the data.

Une application peut émuler la fonctionnalité de mise en cache avec double lecture en implémentant la stratégie Cache-Aside.An application can emulate the functionality of read-through caching by implementing the cache-aside strategy. Cette stratégie charge des données dans le cache à la demande.This strategy loads data into the cache on demand. La figure montre comment utiliser le modèle Cache-Aside pour stocker des données dans le cache.The figure illustrates using the Cache-Aside pattern to store data in the cache.

Utilisation du modèle Cache-Aside pour stocker des données dans le cache

Si une application met à jour les informations, elle peut appliquer la stratégie de double écriture en répercutant la modification dans la banque de données et en invalidant l’élément correspondant dans le cache.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.

Lorsque l’application aura à nouveau besoin de cet élément, la stratégie Cache-Aside permettra de récupérer les données mises à jour dans la banque de données et de les ajouter au cache.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èmes et considérationsIssues and considerations

Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :Consider the following points when deciding how to implement this pattern:

Durée de vie des données mises en cache.Lifetime of cached data. De nombreux caches intègrent une stratégie d’expiration qui invalide les données et les supprime du cache si elles n’ont pas été consultées pendant une certaine période.Many caches implement an expiration policy that invalidates data and removes it from the cache if it's not accessed for a specified period. Pour que la stratégie Cache-Aside soit efficace, assurez-vous que la stratégie d’expiration correspond au modèle d’accès pour les applications qui utilisent les données.For cache-aside to be effective, ensure that the expiration policy matches the pattern of access for applications that use the data. Ne configurez pas un délai d’expiration trop court, car les applications pourraient alors récupérer des données en continu dans la banque de données pour les ajouter au cache.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. De même, ne configurez pas un délai d’expiration trop long pour éviter que les données en cache deviennent obsolètes.Similarly, don't make the expiration period so long that the cached data is likely to become stale. N’oubliez pas que la mise en cache est particulièrement efficace pour des données relativement statiques ou des données qui sont fréquemment lues.Remember that caching is most effective for relatively static data, or data that is read frequently.

Éviction des données.Evicting data. La plupart des caches étant de plus petite taille que les banques de données d’où proviennent les données, ils n’ont parfois d’autre choix que de supprimer des données.Most caches have a limited size compared to the data store where the data originates, and they'll evict data if necessary. La plupart des caches adoptent une stratégie qui consiste à supprimer les données les moins récemment utilisées. Il est néanmoins possible de personnaliser cette stratégie.Most caches adopt a least-recently-used policy for selecting items to evict, but this might be customizable. Configurez la propriété d’expiration globale ainsi que d’autres propriétés du cache et la propriété d’expiration de chaque élément mis en cache pour limiter les coûts associés à la mise en cache.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. Il n’est pas toujours judicieux d’appliquer une stratégie d’éviction globale pour chaque élément présent dans le cache.It isn't always appropriate to apply a global eviction policy to every item in the cache. Par exemple, si la récupération d’un élément mis en cache à partir de la banque de données s’avère très coûteuse, il peut être judicieux de conserver cet élément dans le cache au détriment d’autres éléments fréquemment lus mais moins coûteux.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.

Amorçage du cache.Priming the cache. De nombreuses solutions préremplissent le cache avec des données dont une application est susceptible d’avoir besoin au moment du démarrage.Many solutions prepopulate the cache with the data that an application is likely to need as part of the startup processing. Le modèle Cache-Aside peut toujours être utile si certaines de ces données expirent ou sont supprimées.The Cache-Aside pattern can still be useful if some of this data expires or is evicted.

Cohérence.Consistency. L’implémentation du modèle Cache-Aside ne garantit pas la cohérence entre la banque de données et le cache.Implementing the Cache-Aside pattern doesn't guarantee consistency between the data store and the cache. Un élément de la banque de données peut être modifié à tout moment par un processus externe, et cette modification peut ne pas être répercutée dans le cache jusqu’au prochain chargement de l’élément.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. Dans un système qui réplique les données dans différentes banques de données, ce problème peut s’aggraver si la synchronisation intervient fréquemment.In a system that replicates data across data stores, this problem can become serious if synchronization occurs frequently.

Mise en cache locale (en mémoire) .Local (in-memory) caching. Un cache peut être localement associé à une instance d’application et stocké en mémoire.A cache could be local to an application instance and stored in-memory. Le modèle Cache-Aside peut s’avérer utile dans cet environnement si une application accède aux mêmes données de manière répétée.Cache-aside can be useful in this environment if an application repeatedly accesses the same data. Toutefois, un cache local est privé, ce qui permet aux différentes instances d’application d’avoir chacune une copie des mêmes données en cache.However, a local cache is private and so different application instances could each have a copy of the same cached data. Ces données peuvent rapidement devenir incohérentes entre les caches, et il peut être nécessaire de faire expirer les données conservées dans un cache privé et de les actualiser plus fréquemment.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. Dans ces scénarios, analysez les avantages d’utiliser un mécanisme de mise en cache partagé ou distribué.In these scenarios, consider investigating the use of a shared or a distributed caching mechanism.

Quand utiliser ce modèleWhen to use this pattern

Utilisez ce modèle dans les situations suivantes :Use this pattern when:

  • Un cache ne fournit pas d’opérations de double lecture et de double écriture natives.A cache doesn't provide native read-through and write-through operations.
  • La demande en ressources n’est pas prévisible.Resource demand is unpredictable. Ce modèle permet aux applications de charger des données à la demande.This pattern enables applications to load data on demand. Il n’émet aucune hypothèse sur les données dont aura besoin une application.It makes no assumptions about which data an application will require in advance.

Ce modèle peut ne pas convenir :This pattern might not be suitable:

  • Lorsque le jeu de données mises en cache est statique.When the cached data set is static. Si les données ne tiennent pas dans l’espace de cache disponible, amorcez le cache avec les données au démarrage et appliquez une stratégie qui empêche l’expiration des données.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.
  • Pour mettre en cache les informations d’état de session dans une application web hébergée dans une batterie de serveurs web.For caching session state information in a web application hosted in a web farm. Dans cet environnement, vous devez éviter d’introduire des dépendances basées sur l’affinité client-serveur.In this environment, you should avoid introducing dependencies based on client-server affinity.

ExempleExample

Dans Microsoft Azure vous pouvez utiliser Azure cache for Redims pour créer un cache distribué qui peut être partagé par plusieurs instances d’une application.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.

Les exemples de code suivants utilisent le client StackExchange.Redis. Il s’agit d’une bibliothèque de client Redis écrite pour .NET.This following code examples use the StackExchange.Redis client, which is a Redis client library written for .NET. Pour vous connecter à un cache Azure pour l’instance redims, appelez ConnectionMultiplexer.Connect la méthode statique et transmettez la chaîne de connexion.To connect to an Azure Cache for Redis instance, call the static ConnectionMultiplexer.Connect method and pass in the connection string. La méthode renvoie un élément ConnectionMultiplexer qui représente la connexion.The method returns a ConnectionMultiplexer that represents the connection. Pour partager une instance ConnectionMultiplexer dans votre application, vous pouvez utiliser une propriété statique qui renvoie une instance connectée, comme dans l’exemple suivant.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. Cette approche fournit une méthode thread-safe permettant d’initialiser une seule instance connectée.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;

La méthode GetMyEntityAsync dans l’exemple de code suivant illustre une implémentation du modèle Cache-Aside.The GetMyEntityAsync method in the following code example shows an implementation of the Cache-Aside pattern. Cette méthode récupère un objet à partir du cache à l’aide de l’approche en double lecture.This method retrieves an object from the cache using the read-through approach.

Un objet est identifié en utilisant un identifiant entier comme clé.An object is identified by using an integer ID as the key. La méthode GetMyEntityAsync tente de récupérer un élément avec cette clé à partir du cache.The GetMyEntityAsync method tries to retrieve an item with this key from the cache. Si un élément correspondant est trouvé, celui-ci est renvoyé.If a matching item is found, it's returned. Si aucune correspondance n’est trouvée dans le cache, la méthode GetMyEntityAsync récupère l’objet à partir d’une banque de données, l’ajoute au cache, puis le renvoie.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. Le code qui lit les données de la banque de données n’est pas présenté ici, car il varie selon la banque de données.The code that actually reads the data from the data store is not shown here, because it depends on the data store. Notez que l’élément mis en cache est configuré pour expirer afin qu’il ne devienne pas obsolète dans le cas où il serait mis à jour à un autre endroit.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;
}

Les exemples utilisent le cache Azure pour que les Redims accèdent au magasin et récupèrent des informations à partir du cache.The examples use Azure Cache for Redis to access the store and retrieve information from the cache. Pour plus d’informations, consultez utilisation du cache Azure pour les méthodes ReDim et comment créer une application Web avec le cache Azure pour lesinversion.For more information, see Using Azure Cache for Redis and How to create a Web App with Azure Cache for Redis.

La méthode UpdateEntityAsync illustrée ci-dessous montre comment invalider un objet dans le cache lorsque sa valeur est modifiée par l’application.The UpdateEntityAsync method shown below demonstrates how to invalidate an object in the cache when the value is changed by the application. Le code met à jour la banque de données d’origine, puis supprime l’élément en cache du cache.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.
}

Notes

L’ordre dans lequel sont effectuées les étapes est important.The order of the steps is important. Mettez à jour la banque de données avant de supprimer l’élément du cache.Update the data store before removing the item from the cache. Si vous supprimez d’abord l’élément mis en cache, un client pourrait avoir le temps d’extraire l’élément avant que la banque de données ne soit mise à jour.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. En raison de cette absence dans le cache (l’élément a été supprimé du cache), la version antérieure de l’élément serait extraite de la banque de données et ajoutée au cache.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. On obtiendrait donc des données en cache obsolètes.The result will be stale cache data.

Les informations suivantes peuvent également être pertinentes durant l’implémentation de ce modèle :The following information may be relevant when implementing this pattern:

  • Recommandations en matière de cache.Caching Guidance. Fournit des informations supplémentaires sur la façon dont vous pouvez mettre en cache des données dans une solution cloud, ainsi que les points à prendre en compte lorsque vous implémentez un cache.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.

  • Manuel d’introduction à la cohérence des données.Data Consistency Primer. Les applications cloud utilisent généralement des données réparties dans plusieurs banques de données.Cloud applications typically use data that's spread across data stores. La gestion et la maintenance de la cohérence des données dans cet environnement constituent un aspect essentiel du système, notamment par rapport aux problèmes de concurrence et de disponibilité pouvant survenir.Managing and maintaining data consistency in this environment is a critical aspect of the system, particularly the concurrency and availability issues that can arise. Ce manuel décrit les problèmes de cohérence des données distribuées et explique comment une application peut implémenter la cohérence éventuelle pour garantir la disponibilité des données.This primer describes issues about consistency across distributed data, and summarizes how an application can implement eventual consistency to maintain the availability of data.