Redis Cluster : Architecture, Déploiement et Opérations

Introduction aux Systèmes NoSQL et Redis

Les bases de données NoSQL, en particulier les magasins de clé-valeur, ont gagné en popularité pour leur capacité à gérer des volumes massifs de données et des débits élevés. Parmi elles, Redis se distingue comme un choix privilégié pour la mise en cache, les bases de données et les courtiers de messages.

Capacités Principales de Redis

  • Types de Données Variés : Prend en charge les chaînes, hachages, listes, ensembles, ensembles triés, bitmaps et hyperloglogs.
  • Persistance des Données : Offre des mécanismes RDB (snapshot) et AOF (journal d'opérations) pour sauvegarder les données sur disque.
  • Stratégies de Gestion Mémoire : Diverses politiques d'éviction pour optimiser l'utilisation de la RAM.
  • Transactions Atomiques : Supporte des opérations groupées avec des garanties transactionnelles légères.
  • Messagerie Avancée : Fonctionnalités de publication/abonnement pour les architectures de microservices.
  • Haute Disponibilité : Architectures maître-réplique et Sentinel pour la tolérance aux pannes.
  • Distribution Horizontale : Support natif pour le clustering distribué.

Comparaison des Solutions de Cache en Entreprise

Historiquement, plusieurs solutions de cache ont été utilisées en entreprise :

Memcached

  • Avantages : Excellentes performances en lecture/écriture pour des données simples, architecture multi-cœurs/multi-threads.
  • Inconvénients : Aucune persistance, la gestion du cluster est côté client, moins de types de données.

Redis

  • Avantages : Performances élevées, nombreux types de données, persistance, haute disponibilité, clustering distribué, architecture single-thread très efficace.
  • Inconvénients : Historiquement, les performances multi-threads pures étaient légèrement inférieures à Memcached pour certaines charges de travail, bien que cela ait évolué avec les versions récentes.

Redis est souvent préféré pour les applications nécessitant une plus grande flexibilité des données et des garanties de persistance, comme dans les plateformes de commerce électronique, les réseaux sociaux et les jeux en ligne.

Installation et Configuration Basique de Redis

Redis est développé en langage C, ce qui lui confère une vitesse et une efficacité remarquables. Son architecture mono-thread simplifie la gestion de la concurrence.

Processus d'Installation

Pour installer Redis, il est généralement recommandé de le compiler à partir des sources pour une performance optimale. Les étapes sont les suivantes :

# Télécharger l'archive depuis le site officiel
wget http://download.redis.io/releases/redis-7.0.5.tar.gz

# Extraire l'archive
tar xzf redis-7.0.5.tar.gz
mv redis-7.0.5 redis

# Installer les dépendances (GCC, make, etc.)
yum install -y gcc make automake autoconf libtool # Pour systèmes basés sur RPM
# ou apt install -y gcc make automake autoconf libtool # Pour systèmes basés sur Debian

# Compiler Redis
cd redis
make

# Installer les binaires dans un emplacement standard (optionnel, mais recommandé)
make install

# Ajouter les binaires au PATH (si non installés via make install)
echo 'export PATH=/path/to/redis/src:$PATH' >> ~/.bashrc
source ~/.bashrc

Configuraton d'une Instance Redis

Une configuration de base pour un service Redis autonome peut être créée comme suit :

mkdir -p /opt/redis_data/6379
cat > /opt/redis_data/6379/redis.conf <<EOF
daemonize yes
bind 127.0.0.1
port 6379
logfile /opt/redis_data/6379/redis_6379.log
dir /opt/redis_data/6379
dbfilename dump_6379.rdb
protected-mode yes
EOF

# Démarrer le serveur Redis avec la configuration
redis-server /opt/redis_data/6379/redis.conf

  • daemonize yes : Exécute Redis en arrière-plan.
  • bind 127.0.0.1 : N'écoute que sur l'interface locale par défaut. Pour un accès externe, spécifiez l'IP du serveur ou 0.0.0.0 (attention à la sécurité).
  • port 6379 : Le port d'écoute.
  • logfile : Chemin du fichier journal.
  • dir : Répertoire de travail pour les fichiers de persistance.
  • dbfilename : Nom du fichier RDB pour la persistance.
  • protected-mode yes : Active le mode protégé, limitant l'accès aux clients locaux sans configuration explicite de bind ou requirepass. Il est fortement recommandé de le laisser activé ou de configurer un mot de passe.

Sécurisation de l'Accès

Pour sécuriser votre instance Redis, vous pouvez définir un mot de passe et lier le serveur à une adresse IP spécifique :

echo "bind 10.0.0.10 127.0.0.1" >> /opt/redis_data/6379/redis.conf
echo "requirepass votre_mot_de_passe_secret" >> /opt/redis_data/6379/redis.conf

# Redémarrer Redis pour appliquer les changements
redis-cli -p 6379 shutdown
redis-server /opt/redis_data/6379/redis.conf

Pour se connecter avec authentification :

redis-cli -p 6379 -a votre_mot_de_passe_secret
# Ou après la connexion
redis-cli -p 6379
AUTH votre_mot_de_passe_secret

Persistance des Données Redis

Redis propose deux principaux mécanismes pour sauvegarder les données en mémoire sur disque : RDB et AOF.

RDB (Redis Database Backup)

Le mode RDB crée des instantanés (snapshots) de l'ensemble du jeu de données à des intervalles spécifiés. C'est un format binaire compact.

  • Avantages :
    • Très rapide pour la restauration et les sauvegardes.
    • Compact et efficace pour la réplication maître-réplique.
  • Inconvénients :
    • Risque de perte de données entre deux instantanés en cas de crash.

Configuration exemple dans redis.conf :

save 900 1    # Sauvegarde si 1 changement en 15 minutes
save 300 10   # Sauvegarde si 10 changements en 5 minutes
save 60 10000 # Sauvegarde si 10000 changements en 60 secondes
dbfilename mydump.rdb
dir /opt/redis_data/6379

AOF (Append-Only File)

Le mode AOF enregistre chaque commande d'écriture reçue par le serveur sous forme de journal. Au redémarrage, Redis rejoue ces commandes pour reconstruire l'état des données.

  • Avantages :
    • Minimise la perte de données (peut être configuré pour chaque écriture).
    • Le fichier AOF est lisible par l'homme.
  • Inconvénients :
    • Le fichier AOF est généralement plus grand que le RDB.
    • La restauration peut être plus lente que RDB.

Configuration exemple dans redis.conf :

appendonly yes
appendfsync everysec  # Synchronise le fichier AOF toutes les secondes (bon compromis performance/sécurité)
# appendfsync always  # Synchronise à chaque écriture (très sûr, mais lent)
# appendfsync no      # Laisse l'OS gérer la synchronisation (rapide, moins sûr)

Combinaison des Deux

Depuis Redis 4.0, il est possible de combiner RDB et AOF (mode hybride) pour tirer parti des avantages de chacun : le fichier AOF contient un snapshot RDB au démarrage, suivi des commandes AOF incrémentales, ce qui accélère le redémarrage tout en assurant une meilleure résilience. Pour l'activer, il suffit d'avoir appendonly yes et aof-use-rdb-preamble yes (par défaut depuis Redis 5).

Types de Données Fondamentaux de Redis

Redis prend en charge un large éventail de types de données, chacun optimisé pour des cas d'utilisation spécifiques.

Opérations Génériques sur les Clés

Avant de plonger dans les types spécifiques, voici quelques commandes universelles pour la gestion des clés :

# Lister les clés (utiliser avec prudence en production sur de grands datasets)
KEYS user:*
TYPE maClef               # Retourne le type de valeur stockée
EXPIRE maClef 30          # Définit une expiration de 30 secondes
TTL maClef                # Retourne le temps de vie restant en secondes
PERSIST maClef            # Supprime l'expiration
DEL maClef                # Supprime une clé
EXISTS maClef             # Vérifie l'existence d'une clé
RENAME ancienneClef nouvelleClef # Renomme une clé

Chaînes (Strings)

Le type le plus simple, stockant une séquence d'octets. Idéal pour les sessions, les compteurs ou les données binaires.

Exemples d'Opérations

SET utilisateur:123 "Alice"         # Définit une valeur
GET utilisateur:123                 # Récupère la valeur
MSET user:1 "Bob" user:2 "Charlie"  # Définit plusieurs clés en une fois
INCR visites:page_accueil           # Incrémente un compteur
DECR solde:compte:456               # Décrémente un compteur
APPEND message " World"             # Ajoute à une chaîne existante

Hachages (Hashes)

Permettent de stocker des paires champ-valeur au sein d'une seule clé. Similaire aux objets JSON ou aux enregistrements de base de données.

Exemples d'Opérations

HSET produit:789 nom "Ordinateur Portable" prix 1200 stock 50
HGET produit:789 nom                   # Récupère un champ spécifique
HMGET produit:789 nom prix             # Récupère plusieurs champs
HGETALL produit:789                    # Récupère tous les champs et leurs valeurs
HINCRBY produit:789 stock -5           # Décrémente le stock de 5
HDEL produit:789 prix                  # Supprime un champ

Listes (Lists)

Des collections ordonnées de chaînes. Utiles pour les files d'attente, les historiques ou les flux d'actualités.

Exemples d'Opérations

LPUSH historique:user:101 "Page A" "Page B" "Page C" # Ajoute des éléments à gauche (tête)
RPUSH file:taches "Tache 1" "Tache 2"                # Ajoute des éléments à droite (queue)
LPOP historique:user:101                             # Retire et retourne l'élément le plus à gauche
RPOP file:taches                                     # Retire et retourne l'élément le plus à droite
LRANGE historique:user:101 0 2                       # Récupère les 3 premiers éléments (index 0 à 2)

Ensembles (Sets)

Collections non ordonnées de chaînes uniques. Idéales pour les tags, les amis ou les éléments uniques.

Exemples d'Opérations

SADD utilisateurs:premium "user:1" "user:5" "user:10"
SADD utilisateurs:actifs "user:5" "user:15" "user:20"
SMEMBERS utilisateurs:premium           # Liste tous les membres
SISMEMBER utilisateurs:premium "user:1" # Vérifie si un membre existe
SINTER utilisateurs:premium utilisateurs:actifs # Intersection (utilisateurs à la fois premium et actifs)
SUNION utilisateurs:premium utilisateurs:actifs # Union (tous les utilisateurs premium ou actifs)
SDIFF utilisateurs:premium utilisateurs:actifs  # Différence (utilisateurs premium mais pas actifs)
SREM utilisateurs:premium "user:1"      # Retire un membre

Ensembles Triés (Sorted Sets)

Similaires aux ensembles, mais chaque membre est associé à un score flottant, permettant de les ordonner. Parfaits pour les classements (leaderboards) ou les éléments prioritaires.

Exemples d'Opérations

ZADD classement:jeu 100 "JoueurA" 250 "JoueurB" 180 "JoueurC"
ZINCRBY classement:jeu 50 "JoueurA" # Augmente le score de JoueurA de 50
ZRANGE classement:jeu 0 -1 WITHSCORES # Affiche le classement du plus petit au plus grand score
ZREVRANGE classement:jeu 0 2 WITHSCORES # Affiche le top 3 (scores les plus élevés)
ZSCORE classement:jeu "JoueurB"     # Récupère le score d'un joueur

Publication/Abonnement (Pub/Sub)

Redis peut fonctionner comme un système de messagerie, où les clients s'abonnent à des canaux et reçoivent les messages publiés sur ces canaux.

Exemple d'Utilisation

# Fenêtre 1 (Abonné)
SUBSCRIBE alertes_systeme

# Fenêtre 2 (Éditeur)
PUBLISH alertes_systeme "Serveur web en surcharge!"

Les abonnés ne reçoivent que les messages publiés après leur abonnement. Il n'y a pas de persistance des messages pour les abonnés déconnectés.

Transactions Redis (Optimistic Locking)

Les transactions Redis permettent d'exécuter un groupe de commandes de manière atomique. Elles sont basées sur une file d'attente et un mécanisme de verrouillage optimiste.

Processus Transactionnel

WATCH mon_compteur # Surveille 'mon_compteur' pour les modifications concurrentes
MULTI              # Démarre la transaction (les commandes sont mises en file d'attente)
INCR mon_compteur
SET message "Transaction executée"
EXEC               # Exécute toutes les commandes en file d'attente.
                   # Si 'mon_compteur' a été modifié par un autre client depuis WATCH,
                   # la transaction échoue.

Si la commande DISCARD est exécutée avant EXEC, toutes les commandes en file d'attente sont abandonnées. Les transactions Redis garantissant que toutes les commandes d'une transaction sont exécutées séquentielement et atomiquement, ou aucune ne l'est, à moins qu'une commande en file d'attente ne soit syntaxiquement incorrecte.

Réplication Maître-Réplique (Master-Replica)

La réplication permet d'avoir des copies des données Redis, améliorant la lecture des performances et offrant une base pour la haute disponibilité.

Principe de Fonctionnement

  1. Une réplique se connecte au maître et envoie une commande PSYNC (synchronisation partielle) ou SYNC (synchronisation complète).
  2. Le maître génère un snapshot RDB de son jeu de données et l'envoie à la réplique.
  3. Pendant que le RDB est transféré, le maître met en tampon toutes les commandes d'écriture reçues.
  4. La réplique charge le snapshot RDB.
  5. Le maître envoie les commandes mises en tampon à la réplique, qui les exécute.
  6. Une fois synchronisée, la réplique reçoit en continu toutes les nouvelles commandes d'écriture du maître.

Configuration d'un Cluster Maître-Réplique

Nous allons configurer trois instances : 6380 (maître), 6381 et 6382 (répliques).

Fichiers de Configuration

# Configuration du maître (6380)
cat > /opt/redis_data/6380/redis.conf <<EOF
port 6380
daemonize yes
pidfile /opt/redis_data/6380/redis_6380.pid
logfile "/opt/redis_data/6380/redis_6380.log"
dbfilename dump_6380.rdb
dir /opt/redis_data/6380
requirepass mysecurepass
masterauth mysecurepass
EOF

# Configuration de la première réplique (6381)
cat > /opt/redis_data/6381/redis.conf <<EOF
port 6381
daemonize yes
pidfile /opt/redis_data/6381/redis_6381.pid
logfile "/opt/redis_data/6381/redis_6381.log"
dbfilename dump_6381.rdb
dir /opt/redis_data/6381
requirepass mysecurepass
masterauth mysecurepass
EOF

# Configuration de la seconde réplique (6382)
cat > /opt/redis_data/6382/redis.conf <<EOF
port 6382
daemonize yes
pidfile /opt/redis_data/6382/redis_6382.pid
logfile "/opt/redis_data/6382/redis_6382.log"
dbfilename dump_6382.rdb
dir /opt/redis_data/6382
requirepass mysecurepass
masterauth mysecurepass
EOF

Démarrage et Connexion

redis-server /opt/redis_data/6380/redis.conf
redis-server /opt/redis_data/6381/redis.conf
redis-server /opt/redis_data/6382/redis.conf

# Configurer 6381 et 6382 comme répliques de 6380
redis-cli -p 6381 -a mysecurepass SLAVEOF 127.0.0.1 6380
redis-cli -p 6382 -a mysecurepass SLAVEOF 127.0.0.1 6380

Vérification de l'État

redis-cli -p 6380 -a mysecurepass INFO replication
redis-cli -p 6381 -a mysecurepass INFO replication

Pour désactiver la réplication sur une réplique :

redis-cli -p 6382 -a mysecurepass SLAVEOF NO ONE

Redis Sentinel pour la Haute Disponibilité

Redis Sentinel est un système de surveillance qui assure la haute disponibilité en détectant les pannes du maître et en promouvant automatiquement une réplique au rang de nouveau maître.

Fonctionnalités de Sentinel

  • Surveillance : Vérifie constamment que les instances Redis (maître et répliques) fonctionnent correctement.
  • Notification : Peut alerter les administrateurs en cas de problème.
  • Basculement Automatique (Failover) : Déclenche la promotion d'une réplique en maître lorsqu'un maître est jugé défaillant.
  • Reconfiguration : Met à jour la configuration des répliques pour qu'elles suivent le nouveau maître.

Déploiement de Redis Sentinel

Un quorum de Sentinels est recommandé pour éviter les faux positifs. Ici, nous configurons un seul Sentinel pour l'exemple.

Configuration de Sentinel

mkdir -p /opt/redis_sentinel/26380
cat > /opt/redis_sentinel/26380/sentinel.conf <<EOF
port 26380
dir "/opt/redis_sentinel/26380"
# Surveille un maître nommé 'monmaitre' à 127.0.0.1:6380, avec un quorum de 1
sentinel monitor monmaitre 127.0.0.1 6380 1
# Temps en ms après lequel un maître est considéré comme hors ligne si non-répondant
sentinel down-after-milliseconds monmaitre 5000
# Mot de passe pour l'authentification au maître
sentinel auth-pass monmaitre mysecurepass
EOF

Démarrage de Sentinel

redis-sentinel /opt/redis_sentinel/26380/sentinel.conf &> /tmp/sentinel.log &

Test de Basculement

Pour tester, arrêtez l'instance Redis maître (6380) :

redis-cli -p 6380 -a mysecurepass shutdown

Observez les logs de Sentinel et vérifiez l'état de réplication des autres instances : une réplique (par exemple 6381) devrait être promue maître.

redis-cli -p 6381 -a mysecurepass INFO replication

Une fois l'ancien maître (6380) redémarré, il devrait automatiquement devenir une réplique du nouveau maître.

redis-server /opt/redis_data/6380/redis.conf

Redis Cluster

Redis Cluster permet de distribuer automatiquement les données sur plusieurs nœuds Redis, offrant une scalabilité horizontale et une haute disponibilité sans Sentinel externe.

Principes de Communication et Distribution des Données

  • Protocole Gossip : Les nœuds du cluster communiquent entre eux via le protocole Gossip (messages PING, PONG, MEET, FAIL) pour découvrir d'autres nœuds, vérifier leur état de santé et échanger des métadonnées du cluster. Le port de communication du cluster est le port de base + 10000 (ex: 7000 devient 17000).
  • Slots de Hachage : Le cluster utilise 16384 "slots de hachage". Chaque clé est mappée à l'un de ces slots en utilisant un algorithme CRC16(clé) % 16384.
  • Distribution des Slots : Ces 16384 slots sont distribués entre les nœuds maîtres du cluster. Chaque maître est responsable d'une plage de slots.
  • Redirection Client : Si un client tente d'accéder à une clé dont le slot est géré par un autre nœud, le nœud actuel répondra avec une redirection MOVED, indiquant au client le nœud correct.

Haute Disponibilité du Cluster

Chaque maître dans un cluster Redis peut avoir une ou plusieurs répliques. En cas de défaillance d'un maître, une de ses répliques est automatiquement promue pour prendre sa place. Le cluster continue de fonctionner tant qu'une majorité de maîtres (et leurs répliques) sont disponibles.

Déploiement d'un Cluster Redis

Un cluster Redis minimal fonctionnel nécessite au moins trois nœuds maîtres, chacun avec au moins une réplique. Nous allons configurer 6 instances Redis pour former 3 maîtres et 3 répliques.

Pré-requis : Ruby et le gem redis

L'outil de gestion de cluster redis-trib.rb (utilisé ici pour la compatibilité avec l'exemple original, mais redis-cli --cluster est préféré pour Redis 5+) nécessite Ruby et le gem redis.

yum install -y ruby rubygems
gem install redis -v 3.3.3 # Ou une version compatible avec votre Redis

Préparation des Répertoires et Configurations

Créez des répertoires et des fichiers de configuration pour chaque instance (ports 7000 à 7005).

mkdir -p /opt/redis_cluster_data/{7000..7005}

# Modèle de configuration pour chaque nœud
# Répétez ce bloc pour les ports 7000 à 7005 en ajustant le port et les chemins.
cat > /opt/redis_cluster_data/7000/redis.conf <<EOF
port 7000
daemonize yes
pidfile /opt/redis_cluster_data/7000/redis_7000.pid
logfile "/opt/redis_cluster_data/7000/redis_7000.log"
dbfilename dump_7000.rdb
dir /opt/redis_cluster_data/7000
protected-mode no
cluster-enabled yes
cluster-config-file nodes-7000.conf # Chaque nœud doit avoir son propre fichier de config de cluster
cluster-node-timeout 5000
appendonly yes
EOF

Assurez-vous que chaque fichier redis.conf est correctement nommé et que les ports, pidfiles, logfiles, dbfilenames et cluster-config-file sont uniques pour chaque instance.

Démarrage des Nœuds

redis-server /opt/redis_cluster_data/7000/redis.conf
redis-server /opt/redis_cluster_data/7001/redis.conf
redis-server /opt/redis_cluster_data/7002/redis.conf
redis-server /opt/redis_cluster_data/7003/redis.conf
redis-server /opt/redis_cluster_data/7004/redis.conf
redis-server /opt/redis_cluster_data/7005/redis.conf

# Vérifiez que tous les nœuds sont démarrés
ps -ef | grep redis-server | grep cluster

Création du Cluster

Utilisez redis-trib.rb pour initialiser le cluster. L'option --replicas 1 indique que chaque maître aura une réplique.

/path/to/redis/src/redis-trib.rb create --replicas 1 \
127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

Confirmez la création en tapant yes.

Vérification de l'État du Cluster

redis-cli -p 7000 cluster nodes
redis-cli -c -p 7000 INFO cluster # Le -c est important pour le mode cluster

Pour tester, insérez et récupérez des données :

redis-cli -c -p 7000 SET maClef "une valeur"
redis-cli -c -p 7000 GET maClef

Le client devrait automatiquement se rediriger vers le nœud approprié.

Gestion des Nœuds du Cluster

Ajout d'un Nouveau Maître

Pour ajouter un nouveau nœud maître (ex: 7006), configurez-le et démarrez-le comme les autres. Ensuite, utilisez add-node :

redis-server /opt/redis_cluster_data/7006/redis.conf
/path/to/redis/src/redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000

Le nouveau nœud est ajouté au cluster, mais il n'a pas encore de slots de hachage. Vous devez lui en attribuer via un reshard.

Re-partitionnement (Resharding) des Slots

Le re-partitionnement permet de déplacer des slots entre les nœuds. Pour attribuer des slots au nouveau nœud 7006 :

/path/to/redis/src/redis-trib.rb reshard 127.0.0.1:7000
# Nombre de slots à déplacer (ex: 1365 slots pour un nouveau maître)
How many slots do you want to move (from 1 to 16384)? 1365
# ID du nœud receveur (récupérez l'ID du nœud 7006 via 'cluster nodes')
What is the receiving node ID? <ID_DU_NOEUD_7006>
# Nœuds sources (tapez 'all' pour prendre des slots de tous les maîtres existants)
Source node #1: all
# Confirmez l'opération

Ajout d'une Réplique à un Maître Existant

Démarrez la nouvelle instance (ex: 7007). Ensuite, utilisez add-node --slave en spécifiant l'ID du maître qu'elle doit répliquer :

redis-server /opt/redis_cluster_data/7007/redis.conf
/path/to/redis/src/redis-trib.rb add-node --slave --master-id <ID_DU_NOEUD_7006> \
127.0.0.1:7007 127.0.0.1:7000

Suppression d'un Nœud

Pour supprimer un nœud maître, vous devez d'abord déplacer tous ses slots de hachage vers d'autres nœuds via un reshard. Ensuite, supprimez le nœud :

# Déplacer les slots du nœud à supprimer (ex: 7006) vers d'autres maîtres
/path/to/redis/src/redis-trib.rb reshard 127.0.0.1:7000
# ... (déplacer tous les slots du nœud 7006)

# Supprimer le nœud maître (ex: 7006)
/path/to/redis/src/redis-trib.rb del-node 127.0.0.1:7006 <ID_DU_NOEUD_7006>

# Supprimer un nœud réplique (ex: 7007)
/path/to/redis/src/redis-trib.rb del-node 127.0.0.1:7007 <ID_DU_NOEUD_7007>

Outils d'Administration Redis

Migration de Données avec redis-migrate-tool

Cet outil est utile pour migrer des données d'une instance Redis (ou cluster) à une autre.

# Installation
git clone https://github.com/vipshop/redis-migrate-tool.git
cd redis-migrate-tool
autoreconf -fvi
./configure
make && make install

# Exemple de configuration (migration d'une instance 6379 vers un cluster à partir du nœud 7000)
cat > /tmp/migration_config.conf <<EOF
[source]
type: single
servers:
- 10.0.0.10:6379

[target]
type: redis cluster
servers:
- 10.0.0.10:7000

[common]
listen: 0.0.0.0:8889
source_safe: true
EOF

# Exécution de la migration
redis-migrate-tool -c /tmp/migration_config.conf

Analyse des Fichiers RDB avec redis-rdb-tools

Cet outil Python permet d'analyser le contenu d'un fichier RDB pour comprendre l'utilisation de la mémoire par les clés.

# Installation
pip install rdbtools # Ou installez depuis les sources GitHub

# Analyse et export au format CSV
rdb -c memory /opt/redis_cluster_data/7000/dump_7000.rdb -f /tmp/memory_report_7000.csv

# Tri par taille de clé
awk -F ',' '{print $4, $2, $3, $1}' /tmp/memory_report_7000.csv | sort -rh > /tmp/sorted_memory_report.txt

Intégration de Redis avec Python

Connexion à une Instance Unique

Le client Python redis-py est le plus courant.

import redis

# Connexion à une instance autonome
r_single = redis.StrictRedis(host='127.0.0.1', port=6379, db=0, password='mysecurepass')

# Opérations
r_single.set('produit_alpha', 'description_alpha')
print(r_single.get('produit_alpha'))

Connexion à un Cluster Sentinel

Pour un setup Maître-Réplique géré par Sentinel :

from redis.sentinel import Sentinel

sentinels = [('127.0.0.1', 26380)]
sentinel = Sentinel(sentinels, socket_timeout=0.1, password='mysecurepass')

# Obtenir une connexion au maître pour les écritures
master = sentinel.master_for('monmaitre', socket_timeout=0.1, password='mysecurepass')
master.set('config_clef', 'valeur_speciale')

# Obtenir une connexion à une réplique pour les lectures
replica = sentinel.slave_for('monmaitre', socket_timeout=0.1, password='mysecurepass')
print(replica.get('config_clef'))

Connexion à un Cluster Redis

Le client redis-py-cluster (ou redis.RedisCluster dans redis-py plus récent) est utilisé.

from rediscluster import RedisCluster # Ou from redis import RedisCluster pour redis-py >= 3.x

# Nœuds de démarrage du cluster
startup_nodes = [
    {"host": "127.0.0.1", "port": "7000"},
    {"host": "127.0.0.1", "port": "7001"},
    # ... ajoutez tous les nœuds de votre cluster
]

# Connexion au cluster
# decode_responses=True est essentiel pour Python 3 afin d'obtenir des chaînes de caractères
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)

# Opérations
rc.set("test_cluster_key", "valeur_cluster")
print(rc.get("test_cluster_key"))

Problématiques Courantes de Cache

Cache Penetration (Pénétration de Cache)

Se produit lorsqu'une application tente d'accéder à une clé qui n'existe ni dans le cache, ni dans la base de données. Des requêtes massives pour des clés inexistantes peuvent surcharger la base de données.

Solutions :

  • Filtre de Bloom : Utiliser un filtre de Bloom pour stocker une représentation compacte de toutes les clés existantes. Si le filtre indique qu'une clé n'existe probablement pas, la requête peut être bloquée avant d'atteindre le cache ou la DB.
  • Mise en Cache des Valeurs Nulles : Si une clé n'est pas trouvée dans la DB, stocker une valeur "nulle" ou un marqueur d'inexistence dans le cache pour une courte durée.

Cache Avalanche (Avalanche de Cache)

Survient lorsque de nombreuses clés de cache expirent simultanément, ou qu'un nœud de cache tombe en panne. Cela entraîne une cascade de requêtes vers la base de données sous-jacente, pouvant provoquer une panne.

Solutions :

  • Temps d'Expiration Aléatoires : Ajouter un petit décalage aléatoire aux temps d'expiration des clés pour éviter des expirations groupées.
  • Architecture Haute Disponibilité : Utiliser Redis Sentinel ou Redis Cluster pour minimiser l'impact des pannes de nœuds de cache.
  • Pré-chargement du Cache : Recharger proactivement les données populaires dans le cache avant leur expiration.

Script de Gestion Redis

Un script Bash pour gérer les instances Redis de manière centralisée.

#!/bin/bash

# Fonction d'affichage de l'usage
afficher_usage() {
    echo "Usage: $0 {demarrer|stopper|redemarrer|connexion|statut|journal} [PORT]"
    echo "  PORT est facultatif, par défaut 6379."
}

# Définition du port Redis
PORT_REDIS=${2:-6379} # Utilise le deuxième argument, sinon 6379

# Définition des chemins
DIR_BASE="/opt/redis_instances/redis_${PORT_REDIS}"
FICHIER_CONF="${DIR_BASE}/config/redis_${PORT_REDIS}.conf"
FICHIER_LOG="${DIR_BASE}/logs/redis_${PORT_REDIS}.log"

# Fonctions de commande
demarrer_instance() {
    echo "Démarrage de l'instance Redis sur le port ${PORT_REDIS}..."
    redis-server "$FICHIER_CONF"
    statut_instance
}

stopper_instance() {
    echo "Arrêt de l'instance Redis sur le port ${PORT_REDIS}..."
    redis-cli -p "$PORT_REDIS" shutdown
    statut_instance
}

connexion_instance() {
    echo "Connexion à Redis sur le port ${PORT_REDIS}..."
    redis-cli -p "$PORT_REDIS"
}

statut_instance() {
    echo "Statut des processus Redis :"
    ps -ef | grep "redis-server .*:${PORT_REDIS}" | grep -v grep
}

afficher_journal() {
    echo "Affichage du journal pour l'instance Redis sur le port ${PORT_REDIS} (Ctrl+C pour quitter) :"
    tail -f "$FICHIER_LOG"
}

# Logique principale du script
case "$1" in
    demarrer)
        demarrer_instance
        ;;
    stopper)
        stopper_instance
        ;;
    redemarrer)
        stopper_instance
        demarrer_instance
        ;;
    connexion)
        connexion_instance
        ;;
    statut)
        statut_instance
        ;;
    journal)
        afficher_journal
        ;;
    *)
        afficher_usage
        exit 1
        ;;
esac

Surveillance des Clés Expirables

Un défi opérationnel est de surveiller les clés avec un temps de vie (TTL) afin d'éviter des comportements inattendus, comme la perte prématurée de coupons ou de sessions. Il est crucial d'éviter des commandes comme KEYS * en production, car elles bloquent le serveur.

Approche Sûre : Utiliser la commande SCAN pour itérer sur les clés sans bloquer le serveur.

#!/bin/bash

FICHIER_LISTE_CLEFS="liste_cles_a_surveiller.txt"
FICHIER_SORTIE="cles_expirees_detectees.log"
REDIS_HOST="127.0.0.1"
REDIS_PORT="6379"

# Efface le fichier de sortie précédent
> "$FICHIER_SORTIE"

echo "Démarrage de la surveillance des clés expirables..."

# Lire chaque motif de clé à surveiller
while IFS= read -r motif_clef; do
    echo "Recherche pour le motif: $motif_clef"
    CURSEUR=0
    
    # Itérer avec SCAN
    while true; do
        # Exécuter SCAN et capturer le curseur suivant et les clés
        RESULTAT_SCAN=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" SCAN "$CURSEUR" MATCH "${motif_clef}*" COUNT 1000)
        
        # Le curseur est sur la première ligne, les clés sur les lignes suivantes
        NOUVEAU_CURSEUR=$(echo "$RESULTAT_SCAN" | head -n 1)
        CLEFS_TROUVEES=$(echo "$RESULTAT_SCAN" | tail -n +2)
        
        # Vérifier le TTL pour chaque clé trouvée
        if [ -n "$CLEFS_TROUVEES" ]; then
            echo "$CLEFS_TROUVEES" | while IFS= read -r clef_trouvee; do
                TTL_CLEF=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" TTL "$clef_trouvee")
                if [ "$TTL_CLEF" -eq -1 ]; then
                    echo "Clé persistante (TTL -1): $clef_trouvee (motif: $motif_clef)" | tee -a "$FICHIER_SORTIE"
                elif [ "$TTL_CLEF" -eq -2 ]; then
                    echo "Clé non trouvée ou déjà expirée (TTL -2): $clef_trouvee (motif: $motif_clef)" | tee -a "$FICHIER_SORTIE"
                elif [ "$TTL_CLEF" -lt 60 ]; then # Exemple: alerte si moins de 60 secondes
                    echo "Clé avec TTL court ($TTL_CLEF s): $clef_trouvee (motif: $motif_clef)" | tee -a "$FICHIER_SORTIE"
                fi
            done
        fi
        
        # Si le nouveau curseur est 0, nous avons parcouru toutes les clés
        if [ "$NOUVEAU_CURSEUR" -eq 0 ]; then
            break
        fi
        CURSEUR="$NOUVEAU_CURSEUR"
    done
done < "$FICHIER_LISTE_CLEFS"

echo "Surveillance terminée. Résultats dans $FICHIER_SORTIE"

Ce script nécessite un fichier liste_cles_a_surveiller.txt contenant les motifs de clés (ex: session:*, coupon:*) à analyser, un par ligne.

Étiquettes: Redis NoSQL Cluster Sentinel réplication

Publié le 19 juillet à 01h04