Stratégies de mise en cache - Amazon ElastiCache for Redis

Stratégies de mise en cache

Dans la rubrique suivante, vous trouverez des stratégies pour remplir et maintenir votre cache.

La ou les stratégies que vous souhaitez mettre en œuvre pour remplir et assurer la maintenance de votre cache dépendent des données vous avez mises en cache et des modèles d'accès aux données. Par exemple, vous ne souhaiterez sans doute pas utiliser la même stratégie pour le top 10 d'un jeu sur Internet ou pour des sujets d'actualité. Dans le reste de cette section, nous aborderons les stratégies de maintenance de cache courantes, leurs avantages et leurs inconvénients.

Chargement différé

Comme le nom l'indique, un chargement différé correspond à une stratégie de mise en cache qui charge des données dans la mémoire cache uniquement lorsque c'est nécessaire. Cela fonctionne comme décrit ci-dessous.

Amazon ElastiCache est un magasin clé-valeur en mémoire qui se trouve entre votre application et le magasin de données (base de données) auquel il accède. Chaque fois que votre application demande des données, elle effectue tout d'abord la requête dans la mémoire cache d'ElastiCache. Si les données existent dans le cache et sont à jour, ElastiCache renvoie les données à votre application. Si les données n'existent pas dans le cache ou ont expiré, votre application demande les données à partir de votre magasin de données. Votre magasin de données renvoie ensuite les données à votre application. Votre application enregistre les données reçues du magasin dans le cache. De cette façon, elles peuvent être récupérées plus rapidement la prochaine fois qu'elles sont demandées.

Une correspondance avec le cache se produit lorsque les données sont dans le cache et n'ont pas expiré :

  1. L'application demande des données dans le cache.

  2. Le cache retourne les données à l'application.

Une absence de données dans le cache se produit lorsque les données ne sont pas dans le cache ou ont expiré :

  1. L'application demande des données dans le cache.

  2. Le cache n'a pas les données demandées, un code est donc retourné null.

  3. L'application demande et reçoit les données à partir de la base de données.

  4. L'application met à jour le cache avec les nouvelles données.

Avantages et inconvénients du chargement différé

Les avantages du chargement différé sont les suivants :

  • Seules les données demandées sont mises en cache.

    Dans la mesure où la plupart des données ne sont jamais demandées, le chargement différé évite de remplir le cache avec des données qui ne sont pas nécessaires.

  • Les défaillances de nœud ne sont pas fatales pour votre application.

    Lorsqu'un nœud échoue et qu'il est remplacé par un nœud vide, l'application continue à fonctionner, mais avec une latence accrue. Lorsque les requêtes sont effectuées vers le nouveau nœud, chaque échec de cache entraîne une requête dans la base de données. En même temps, la copie de données est ajoutée au cache afin que les requêtes suivantes soient récupérées à partir du cache.

Les inconvénients du chargement différé sont les suivants :

  • Il y a une pénalité pour les échecs de cache. Chaque échec de cache génère 3 sorties :

    1. Une demande initiale de données à partir du cache

    2. Une requête pour les données dans la base de données

    3. L'enregistrement des données dans le cache

    Ce qui peut générer un retard notable dans l'acheminement des données vers l'application.

  • Données obsolètes.

    Si les données sont écrites dans le cas d'un échec de cache, les données du cache deviennent périmées. Ce résultat se produit car il n'y a pas de mise à jour dans le cache quand les données sont modifiées dans la base de données. Pour résoudre ce problème, vous pouvez utiliser les stratégies Écriture simultanée et Ajout d'une durée de vie.

Exemple de pseudocode de chargement différé

Le code suivant est un exemple de pseudo-code de la logique d'un chargement différé.

// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record == null) customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id) cache.set(customer_id, customer_record) return customer_record

Dans cet exemple, le code d'application qui obtient les données est le suivant.

customer_record = get_customer(12345)

Écriture simultanée

La stratégie d'écriture simultanée permet d'ajouter des données et de mettre à jour les données du cache dès que des données sont enregistrées dans la base de données.

Avantages et les inconvénients de l'écriture simultanée

Les avantages de l'écriture simultanée sont les suivants :

  • Les données dans le cache ne se périment jamais.

    Dans la mesure où les données dans le cache sont mises à jour à chaque enregistrement dans la base de données, les données dans le cache sont toujours actuelles.

  • Pénalité d'écriture vs pénalité de lecture.

    Chaque écriture implique deux sorties :

    1. Une écriture dans le cache

    2. Une écriture dans la base de données

    Ce qui ajoute une latence pour le processus. Cela dit, les utilisateurs finaux acceptent généralement plus facilement la latence lors de l'actualisation que lors de la récupération des données. On sait communément que les mises à jour demandent plus de travail et donc prennent plus de temps.

Les inconvénients de l'écriture simultanée sont les suivants :

  • Données manquantes.

    Si vous mettez en service un nouveau nœud, que ce soit en raison d'une panne de nœud ou d'une mise à l'échelle, il y a des données manquantes. Ces données restent manquantes jusqu'à ce qu'elles soient ajoutées ou mises à jour dans la base de données. Vous pouvez minimiser cela en implémentant le chargement différé avec l'écriture simultanée.

  • Evolution du cache.

    La plupart des données ne sont jamais lues, ce qui est un gaspillage de ressources. En ajoutant une valeur de time to live (TTL), vous pouvez minimiser l'espace perdu.

Exemple de pseudocode d'écriture simultanée

Le code suivant est un exemple de pseudo-code de logique d'écriture simultanée.

// ***************************************** // function that saves a customer's record. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record) return success

Dans cet exemple, le code d'application qui obtient les données est le suivant.

save_customer(12345,{"address":"123 Main"})

Ajout d'une durée de vie

Le chargement différé permet l'existence de données obsolètes, mais n'échouera pas sur les nœuds vides. L'écriture simultanée garantit que les données sont toujours parfaitement à jour, mais peuvent échouer sur des nœuds vides et remplir le cache de données superflues. En ajoutant une time to live (TTL) à chaque écriture, vous pouvez avoir les avantages de chaque stratégie. En même temps, vous pouvez et en grande partie éviter d'encombrer le cache avec des données supplémentaires.

Time to live (TTL) est une valeur entière qui spécifie le nombre de secondes qui doivent s'écouler jusqu'à l'expiration de la clé. Redis peut spécifier des secondes ou des millisecondes pour cette valeur. Lorsqu'une application tente de lire une clé expirée, c'est comme si la clé était introuvable. La base de données est interrogée pour la clé et le cache est mis à jour. Cette approche ne garantit pas qu'une valeur n'est pas obsolète. Cependant, il empêche les données de devenir trop anciennes et exige que les valeurs du cache soient occasionnellement rafraîchies à partir de la base de données.

Pour plus d'informations, consultez la commande Redis set .

Exemples de pseudocode TTL

Le code suivant est un exemple de pseudo-code de logique d'écriture simultanée comportant un un time to live.

// ***************************************** // function that saves a customer's record. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and future reads will have to query the database. // ***************************************** save_customer(customer_id, values) customer_record = db.query("UPDATE Customers WHERE id = {0}", customer_id, values) cache.set(customer_id, customer_record, 300) return success

Le code suivant est un exemple de pseudo-code de logique de chargement différé comportant un time to live.

// ***************************************** // function that returns a customer's record. // Attempts to retrieve the record from the cache. // If it is retrieved, the record is returned to the application. // If the record is not retrieved from the cache, it is // retrieved from the database, // added to the cache, and // returned to the application. // The TTL value of 300 means that the record expires // 300 seconds (5 minutes) after the set command // and subsequent reads will have to query the database. // ***************************************** get_customer(customer_id) customer_record = cache.get(customer_id) if (customer_record != null) if (customer_record.TTL < 300) return customer_record // return the record and exit function // do this only if the record did not exist in the cache OR // the TTL was >= 300, i.e., the record in the cache had expired. customer_record = db.query("SELECT * FROM Customers WHERE id = {0}", customer_id) cache.set(customer_id, customer_record, 300) // update the cache return customer_record // return the newly retrieved record and exit function

Dans cet exemple, le code d'application qui obtient les données est le suivant.

save_customer(12345,{"address":"123 Main"})
customer_record = get_customer(12345)

Rubriques en relation