Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Chargez les données à la demande dans un cache à partir d’une banque de données. 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.
Contexte et problème
Les applications utilisent un cache pour optimiser l’accès répété aux informations contenues dans une banque de données. Toutefois, il est irréaliste de s’attendre à ce que les données mises en cache soient toujours cohérentes avec le magasin de données. Les applications doivent implémenter une stratégie qui permet de s’assurer que les données du cache sont aussi up-to-date que possible. La stratégie doit également être en mesure de détecter le moment où les données mises en cache deviennent obsolètes et de les gérer de manière appropriée.
Solution
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. Dans ces systèmes, une application récupère des données en établissant une référence au cache. Si les données ne se trouvent pas dans le cache, l’application la récupère à partir du magasin de données et l’ajoute au cache. Les modifications apportées aux données contenues dans le cache sont automatiquement répercutées dans la banque de données.
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.
Une application peut émuler la fonctionnalité de mise en cache avec double lecture en implémentant la stratégie Cache-Aside. Cette stratégie charge des données dans le cache à la demande. La figure montre comment utiliser le modèle Cache-Aside pour stocker des données dans le cache.
- L’application détermine si l’élément est actuellement conservé dans le cache en tentant de lire à partir du cache.
- Si l’élément n’est pas actif dans le cache (une absence de cache), l’application récupère l’élément à partir du magasin de données.
- L’application ajoute l’élément au cache, puis le retourne à l’appelant.
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.
Lorsque l’élément est de nouveau nécessaire, la stratégie cache-aside récupère les données mises à jour à partir du magasin de données et l’ajoute au cache.
Problèmes et considérations
Prenez en compte les points suivants lorsque vous choisissez comment implémenter ce modèle :
Durée de vie des données mises en cache. De nombreux caches utilisent une stratégie d’expiration pour invalider les données et les supprimer du cache si elles ne sont pas accessibles pendant une période définie. 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. Ne faites pas trop court, car l’expiration prématurée peut entraîner la récupération continue des données à partir du magasin de données et à l’ajouter au 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. 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.
Éviction des données. La plupart des caches ont une taille limitée par rapport au magasin de données où les données proviennent. Si le cache dépasse sa limite de taille, il supprime les données. La plupart des caches adoptent une stratégie moins récemment utilisée pour sélectionner des éléments à supprimer, mais elles peuvent être personnalisables.
Configuration. La configuration du cache peut être définie globalement et par élément mis en cache. Une seule stratégie d’éviction globale peut ne pas convenir à tous les éléments. Une configuration sur un élément de cache peut être appropriée si un élément est coûteux à récupérer. Dans ce cas, il est judicieux de conserver l’élément dans le cache, même s’il est accessible moins fréquemment que les articles moins chers.
Amorçage du 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. Le modèle Cache-Aside peut toujours être utile si certaines de ces données expirent ou sont supprimées.
Cohérence. L’implémentation du modèle Cache-Aside ne garantit pas la cohérence entre la banque de données et le cache. Par exemple, un processus externe peut modifier un élément dans le magasin de données à tout moment. Cette modification n’apparaît pas dans le cache tant que l’élément ne se charge pas à nouveau. Dans un système qui réplique les données entre les magasins de données, la cohérence peut être difficile si la synchronisation se produit fréquemment.
Mise en cache locale (en mémoire) . Un cache peut être localement associé à une instance d’application et stocké en mémoire. 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. 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. 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. Dans ces scénarios, analysez les avantages d’utiliser un mécanisme de mise en cache partagé ou distribué.
Mise en cache sémantique. Certaines charges de travail peuvent tirer parti de la récupération du cache en fonction de la signification sémantique plutôt que des clés exactes. Cela réduit le nombre de requêtes et de jetons envoyés aux modèles linguistiques. Assurez-vous que les données mises en cache bénéficient de l’équivalence sémantique et ne risquent pas de retourner des réponses non liées ou contiennent des données privées et sensibles. Par exemple, « Quel est mon salaire annuel de retour à domicile ? » est sémantiquement similaire à « Qu’est-ce que mon salaire annuel de retour à la maison ? », mais si demandé par deux utilisateurs différents, la réponse ne doit pas être la même, ni ne souhaitez-vous pas inclure ces données sensibles dans votre cache.
Quand utiliser ce modèle
Utilisez ce modèle dans les situations suivantes :
- Un cache ne fournit pas d’opérations de double lecture et de double écriture natives.
- La demande en ressources n’est pas prévisible. Ce modèle permet aux applications de charger des données à la demande. Il ne fait aucune hypothèse quant aux données dont une application a besoin à l’avance.
Ce modèle peut ne pas convenir :
- Si les données sont sensibles ou liées à la sécurité. Il peut être inapproprié de le stocker dans un cache, en particulier si le cache est partagé entre plusieurs applications ou utilisateurs. Accédez toujours à la source principale des données.
- Lorsque le jeu de données mises en cache est statique. Si les données s’intègrent dans l’espace de cache disponible, primez le cache avec les données au démarrage et appliquez une stratégie qui empêche l’expiration des données.
- Quand la plupart des requêtes ne rencontreraient pas d’accès au cache. Dans ce cas, la surcharge liée à la vérification du cache et au chargement des données peut dépasser les avantages de la mise en cache.
- Lors de la mise en cache des informations d’état de session dans une application web hébergée dans une batterie de serveurs web. Dans cet environnement, vous devez éviter d’introduire des dépendances basées sur l’affinité client-serveur.
Conception de la charge de travail
Un architecte doit évaluer la façon dont le modèle de Cache-Aside peut être utilisé dans une conception pour répondre aux objectifs et principes abordés dans les piliers Azure Well-Architected Framework. Par exemple :
| Pilier | Comment ce modèle soutient les objectifs des piliers. |
|---|---|
| Les décisions relatives à la fiabilité contribuent à rendre votre charge de travail résiliente aux dysfonctionnements et à s’assurer qu’elle retrouve un état de fonctionnement optimal après une défaillance. | La mise en cache crée la réplication des données et, de manière limitée, peut être utilisée pour préserver la disponibilité des données fréquemment consultées si le magasin de données d’origine est temporairement indisponible. En outre, en cas de dysfonctionnement du cache, la charge de travail peut revenir au magasin de données d’origine. - RE :05 Redondance |
| L’efficacité des performances permet à votre charge de travail de répondre efficacement aux demandes grâce à des optimisations de la mise à l’échelle, des données, du code. | L’utilisation d’une cabine de cache améliore les performances pour les données lourdes en lecture qui changent rarement et peuvent tolérer une certaine obsolescence. - PE :08 Performance des données - PE :12 Optimisation continue des performances |
Comme pour toute autre décision de conception, il convient de prendre en compte les compromis par rapport aux objectifs des autres piliers qui pourraient être introduits avec ce modèle.
Exemple
Envisagez d’utiliser Azure Managed Redis pour créer un cache distribué que plusieurs instances d’application peuvent partager.
L’exemple de code suivant utilise le client StackExchange.Redis. Il s’agit d’une bibliothèque de client Redis écrite pour .NET. Pour vous connecter à une instance Redis managée Azure, appelez la méthode statique ConnectionMultiplexer.Connect et passez la chaîne de connexion. La méthode renvoie un élément ConnectionMultiplexer qui représente la connexion. 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. Cette approche fournit une méthode thread-safe permettant d’initialiser une seule instance connectée.
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. Cette méthode récupère un objet à partir du cache à l’aide de l’approche en double lecture.
Un objet est identifié en utilisant un identifiant entier comme clé. La méthode GetMyEntityAsync tente de récupérer un élément avec cette clé à partir du cache. Si un élément correspondant est trouvé, le cache le retourne. 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. Le code qui lit les données du magasin de données n’est pas affiché ici, car il dépend du magasin de données. L’élément mis en cache est configuré pour l’empêcher de devenir obsolète si un autre service ou processus le met à jour.
// 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 Azure Managed Redis pour accéder au magasin et récupérer des informations à partir du cache. Pour plus d’informations, consultez Créer un Redis managé Azure et utiliser Azure Redis dans .NET Core.
La UpdateEntityAsync méthode ci-dessous montre comment invalider un objet dans le cache lorsque l’application modifie la valeur. Le code met à jour la banque de données d’origine, puis supprime l’élément en cache du 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. Mettez à jour la banque de données avant de supprimer l’élément du cache. Si vous supprimez d’abord l’élément mis en cache, il existe une petite fenêtre de temps quand un client peut extraire l’élément avant la mise à jour du magasin de données. Dans ce cas, la récupération entraîne une absence de cache (car l’élément a été supprimé du cache). L’absence de cache entraîne l’extraction de la version antérieure de l’élément à partir du magasin de données et l’ajout dans le cache. Le résultat est des données de cache obsolètes.
Ressources associées
Les informations suivantes peuvent être pertinentes durant l’implémentation de ce modèle :
Le modèle d’application web fiable vous montre comment appliquer le modèle cache-aside aux applications web convergeant vers le cloud.
Recommandations en matière de cache. 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.
Data Consistency Primer (Manuel d’introduction à la cohérence des données). Les applications cloud stockent généralement des données dans plusieurs magasins de données et emplacements. La gestion et la maintenance de la cohérence des données dans cet environnement sont un aspect essentiel du système, en particulier les problèmes de concurrence et de disponibilité qui peuvent survenir. 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.
Utilisez Azure Managed Redis comme cache sémantique. Ce tutoriel vous montre comment implémenter la mise en cache sémantique à l’aide d’Azure Managed Redis.