Bonnes pratiques pour Memorystore pour Redis

Cette page fournit des conseils pour utiliser Memorystore pour Redis de manière optimale. Elle souligne également les problèmes potentiels à éviter.

Pour obtenir la liste des scénarios de dépannage, consultez la page Dépannage.

Exportation RDB

Lorsque vous exportez une sauvegarde RDB, suivez les conseils ci-dessous :

Opérations exigeantes en ressources

Pour les instances Redis de niveau standard, les opérations suivantes utilisent de la mémoire supplémentaire pendant toute la durée de l'opération :

En raison de la réplication, les opérations de mise à niveau de la version, de scaling et de basculement manuel utilisent de la mémoire supplémentaire (pour les instances de niveau standard). Ces opérations suivent le processus de réplication décrit dans la section Comportement de la mise à niveau des instances de niveau standard.

Les opérations d'importation et d'exportation nécessitent de la mémoire supplémentaire en raison du processus Redis dupliqué et de la gestion de données de copie pour écriture associées à ces opérations.

Afin de limiter les inconvénients des opérations exigeantes en ressources, vous devez effectuer les opérations suivantes :

Opérations et scénarios nécessitant une nouvelle tentative de connexion

Les opérations et scénarios suivants interrompent la connexion réseau entre votre réseau et l'instance Redis :

Ces opérations modifient votre instance, ce qui nécessite une interruption temporaire de la connexion. Vous devez mettre en place une logique de nouvelle tentative avec un intervalle exponentiel entre les tentatives avant de pouvoir exécuter ces opérations, afin que votre application se reconnecte automatiquement et continue à fonctionner normalement.

Maintenance de routine

Les instances Memorystore pour Redis font l'objet d'une maintenance périodique. Pour en savoir plus, consultez la stratégie de maintenance de Memorystore pour Redis.

Mettez en œuvre les bonnes pratiques suivantes pour vous préparer à la maintenance de routine :

Gestion de la mémoire

La gestion de la mémoire peut être difficile en raison de la fragmentation de la mémoire bien connue qui se produit avec Redis Open Source. Nous vous recommandons d'abaisser la configuration de maxmemory de votre instance pour vous donner de la surcharge en cas de saturation de la mémoire.

Le meilleur moyen de surveiller la saturation de la mémoire sur votre instance Memorystore est d'utiliser la métrique du taux d'utilisation de la mémoire système. Pour obtenir un guide détaillé sur la gestion de la mémoire pour Memorystore pour Redis, consultez Bonnes pratiques pour la gestion de la mémoire.

Gérer les connexions inactives

Au fil du temps, il est possible que le nombre de connexions à votre instance Memorystore augmente si les connexions ne sont pas correctement fermées. Cela peut avoir des conséquences négatives sur les performances, en particulier si vous utilisez le chiffrement en transit, qui impose des limites sur le nombre maximum de connexions en fonction de votre niveau de capacité. Pour éviter cela, nous vous recommandons d'utiliser le paramètre de configuration Redis timeout, qui vous permet de définir le nombre de secondes avant l'arrêt automatique des connexions clientes inactives.

Noms de ressources Access Transparency

Les données sensibles ne doivent pas être stockées dans les noms de ressources Memorystore pour Redis. Par noms de ressources, nous entendons les noms d'instances Memorystore pour Redis et les métadonnées d'instance, telles que les tags. Il n'est pas garanti que les données stockées dans les noms de ressources soient protégées par Google Cloud Access Transparency. Elles peuvent également être en conflit avec les exigences de conformité Access Transparency de votre organisation.

Connecteur d'accès au VPC sans serveur requis pour certains environnements sans serveur

Certains environnements sans serveur nécessitent un connecteur d'accès au VPC sans serveur pour se connecter à Memorystore pour Redis. Si vous souhaitez vous connecter à l'aide de l'un de ces environnements, configurez le connecteur d'accès au VPC sans serveur pour votre projet.

Mise en réseau

Nous vous recommandons d'utiliser le mode de connexion d'accès aux services privés. Memorystore pour Redis utilise deux modes de connexion : l'accès aux services privés et l'appairage direct. Le mode de connexion d'accès aux services privés simplifie la gestion des plages d'adresses IP et vous permet d'utiliser un VPC partagé si vous le souhaitez.

Une fois que vous avez créé une instance, le mode de connexion ne peut plus être modifié.

Pour en savoir plus, consultez la page Mise en réseau.

Surveillance et alertes

Nous vous recommandons d'utiliser la surveillance et les alertes, car elles vous fournissent des signaux clés sur l'utilisation de la mémoire de votre instance Redis. Elles vous donnent également un aperçu de l'efficacité de réponse de votre instance Redis aux requêtes de cache entrantes.

Vous devez configurer les alertes par défaut suivantes :

Bonnes pratiques concernant l'utilisation du processeur

L'utilisation incorrecte de commandes Redis coûteuses entraîne une latence élevée, une absence de réponse ou des problèmes de connectivité. Les instances de niveau standard offrent une haute disponibilité lors de la reprise après sinistre et s'appuient sur la réplication asynchrone entre les nœuds principal et de réplique. Si l'un des nœuds effectue un traitement de commande coûteux qui bloque le thread principal Redis, la réplication peut être affectée. Si le problème persiste et qu'une panne se produit dans un emplacement, les données les plus récentes écrites dans cet emplacement peuvent ne pas être disponibles dans l'autre emplacement.

Nous vous recommandons d'utiliser Cloud Monitoring pour définir des alertes pour la métrique Secondes de processeur du thread principal (redis.googleapis.com/stats/cpu_utilization_main_thread). Vous pourrez ainsi vous assurer que l'utilisation du processeur ne dépasse pas 0,8 seconde pour le nœud principal ni 0,5 seconde pour chaque nœud répliqué lorsque la réplique est désignée comme réplique en lecture.

Si votre instance Redis dépasse les valeurs recommandées, nous vous conseillons de la mettre à l'échelle vers un niveau de capacité supérieur ou de suivre les instructions de dépannage pour éviter les opérations gourmandes en ressources processeur.

Si votre instance connaît une utilisation élevée du processeur ou si ses ressources sont épuisées (par exemple, en raison d'un nombre trop important de connexions), elle peut se comporter de manière anormale et des métriques externes peuvent manquer.

Commandes gourmandes en ressources

Nous vous recommandons vivement d'éviter d'utiliser des commandes Redis gourmandes en ressources. L'utilisation de ces commandes peut entraîner les problèmes de performances suivants :

  • Latence élevée et délais avant expiration des clients
  • Pression sur la mémoire causée par des commandes qui augmentent l'utilisation de la mémoire
  • Perte de données lors de la réplication et de la synchronisation des nœuds, car le thread principal Redis est bloqué
  • Vérifications de l'état affamées, observabilité et réplication

Le tableau suivant liste des exemples de commandes Redis gourmandes en ressources et vous propose des alternatives plus efficaces.

Catégorie Commande gourmande en ressources Alternative économe en ressources
Exécuter pour l'ensemble de l'espace de clés KEYS SCAN
Exécuter pour une collection de clés de longueur variable LRANGE Limitez la taille de la plage que vous utilisez pour une requête.
ZRANGE Limitez la taille de la plage que vous utilisez pour une requête.
HGETALL HSCAN
SMEMBERS SSCAN
Bloquer l'exécution d'un script EVAL Assurez-vous que votre script ne s'exécute pas indéfiniment.
EVALSHA Assurez-vous que votre script ne s'exécute pas indéfiniment.
Supprimer des fichiers et des liens DEL UNLINK
Publier et s'abonner PUBLISH SPUBLISH
SUBSCRIBE SSUBSCRIBE

Bonnes pratiques concernant le client Redis

Cette section fournit des conseils pour utiliser de manière optimale votre client Redis.

Détecter et gérer les connexions qui ne répondent pas

Nous vous recommandons vivement de configurer votre application cliente pour détecter les connexions non réactives à Memorystore pour Redis. Lorsqu'une connexion qui ne répond pas est détectée, le client doit la réinitialiser. Pour créer une application résiliente, nous vous recommandons les configurations client suivantes :

  • Configurez les paramètres de message keep-alive TCP : définissez les paramètres TCP keepalive time, TCP keepalive interval et TCP keepalive probes afin que les clients détectent et abandonnent de manière proactive les connexions qui ne répondent pas, même lorsqu'elles sont inactives. Par exemple, si vous définissez le paramètre TCP keepalive time sur 30 secondes, TCP keepalive interval sur 10 secondes et TCP keepalive probes sur 3, les clients réinitialisent les connexions inactives qui ne répondent pas en une minute.
  • Configurer les délais d'inactivité TCP : définissez ce délai d'inactivité dans vos clients pour réinitialiser les connexions qui ont des requêtes en attente et qui ne répondent plus. Par exemple, si vous définissez le délai avant expiration sur 15 secondes, les clients réinitialisent les connexions non réactives qui ont des requêtes en attente après 15 secondes.

Bonnes pratiques spécifiques aux clients

Si vous effectuer un scaling horizontal de vos applications, vous pouvez rencontrer des erreurs READONLY sur les commandes d'écriture. Memorystore pour Redis utilise un déploiement non Sentinel avec des points de terminaison statiques, et les clients ne reçoivent pas d'informations sur les rôles dynamiques à l'avance. Si vous utilisez une seule connexion client pour vos points de terminaison principaux et de réplique, votre client peut envoyer accidentellement des commandes d'écriture à la réplique en lecture seule. La réplique renvoie une erreur READONLY, car elle ne peut pas traiter les commandes d'écriture.

Pour éviter le mauvais routage des écritures, n'utilisez pas une seule connexion pour les lectures et les écritures. Séparez plutôt vos opérations en créant les instances client distinctes suivantes :

  • Client principal : se connecter uniquement au point de terminaison principal
  • Client de réplique : ne se connecter qu'au point de terminaison de la réplique

Les onglets suivants vous montrent comment configurer les différents modèles en Go, Java, Node.js et Python.

Go

package main

import (
  "context"
  "fmt"

  "github.com/redis/go-redis/v9"
)

func main() {
ctx := context.Background()

  // Initialize the primary client connecting only to the primary endpoint
  primaryClient := redis.NewClient(&redis.Options{
      Addr:     "PRIMARY_HOST:6379",
      Password: "YOUR_PASSWORD",
      DB:       0,
  })
  defer primaryClient.Close()

  // Initialize the replica client connecting only to the replica endpoint
  replicaClient := redis.NewClient(&redis.Options{
      Addr:     "REPLICA_HOST:6379",
      Password: "YOUR_PASSWORD",
      DB:       0,
  })
  defer replicaClient.Close()

  // Use the primary client for all mutating commands
  err := primaryClient.Set(ctx, "example_key", "example_value", 0).Err()
  if err != nil {
      fmt.Printf("Failed to write to primary: %v\n", err)
  }

  // Use the replica client for all read-only commands
  val, err := replicaClient.Get(ctx, "example_key").Result()
  if err != nil {
      fmt.Printf("Failed to read from replica: %v\n", err)
  } else {
      fmt.Printf("Successfully read value: %s\n", val)
  }
}

Java

@Bean
public RedisConnectionFactory primaryConnectionFactory() {
  RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("PRIMARY_HOST", 6379);
  config.setPassword(RedisPassword.of("YOUR_PASSWORD"));
  return new LettuceConnectionFactory(config);
}

@Bean
public RedisConnectionFactory replicaConnectionFactory() {
  RedisStaticMasterReplicaConfiguration config =
      new RedisStaticMasterReplicaConfiguration("PRIMARY_HOST", 6379);
  config.addNode("REPLICA_HOST", 6379);
  config.setPassword(RedisPassword.of("YOUR_PASSWORD"));

  LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
      .readFrom(ReadFrom.REPLICA_PREFERRED)
      .build();

  return new LettuceConnectionFactory(config, clientConfig);
}

@Bean
public RedisTemplate<String, Object> primaryRedisTemplate(
  @Qualifier("primaryConnectionFactory") RedisConnectionFactory factory) {

  RedisTemplate<String, Object> template = new RedisTemplate<>();
  template.setConnectionFactory(factory);
  return template;
}

@Bean
public RedisTemplate<String, Object> replicaRedisTemplate(
  @Qualifier("replicaConnectionFactory") RedisConnectionFactory factory) {

  RedisTemplate<String, Object> template = new RedisTemplate<>();
  template.setConnectionFactory(factory);
  return template;
}

Node.js

import { createClient } from 'redis';

async function main() {
// Initialize the primary client connecting only to the primary endpoint
const primaryClient = createClient({
  url: 'redis://PRIMARY_HOST:6379',
  password: 'YOUR_PASSWORD'
});

// Initialize the replica client connecting only to the replica endpoint
const replicaClient = createClient({
  url: 'redis://REPLICA_HOST:6379',
  password: 'YOUR_PASSWORD'
});

primaryClient.on('error', (err) => console.error('Primary Client Error', err));
replicaClient.on('error', (err) => console.error('Replica Client Error', err));

await primaryClient.connect();
await replicaClient.connect();

// Use the primary client for all mutating commands
try {
  await primaryClient.set('example_key', 'example_value');
  console.log('Successfully wrote to primary');
} catch (err) {
  console.error('Failed to write to primary:', err);
}

// Use the replica client for all read-only commands
try {
  const val = await replicaClient.get('example_key');
  console.log(`Successfully read value: ${val}`);
} catch (err) {
  console.error('Failed to read from replica:', err);
}

await primaryClient.disconnect();
await replicaClient.disconnect();
}

main();

Python

import redis

def main():
  # Initialize the primary client connecting only to the primary endpoint
  primary_client = redis.Redis(
      host='PRIMARY_HOST',
      port=6379,
      password='YOUR_PASSWORD',
      decode_responses=True
  )

  # Initialize the replica client connecting only to the replica endpoint
  replica_client = redis.Redis(
      host='REPLICA_HOST',
      port=6379,
      password='YOUR_PASSWORD',
      decode_responses=True
  )

  # Use the primary client for all mutating commands
  try:
      primary_client.set('example_key', 'example_value')
      print('Successfully wrote to primary')
  except redis.RedisError as e:
      print(f'Failed to write to primary: {e}')

  # Use the replica client for all read-only commands
  try:
      val = replica_client.get('example_key')
      print(f'Successfully read value: {val}')
  except redis.RedisError as e:
      print(f'Failed to read from replica: {e}')

if __name__ == '__main__':
  main()