Date : 19-12-2025 22:30 (Implémenté 23:40) Priorité : Haute Statut : ✅ TERMINÉ
Mise en place de Redis pour les environnements DEV et PROD :
┌─────────────────────────────────────────────────────────────┐
│ PROD (prod-portainer) │
│ 192.168.1.11 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Redis PROD (Master) │ │
│ │ Port : 6379 │ │
│ │ Memory : 1 Go max │ │
│ │ Persistence : AOF + RDB │ │
│ │ Data : /mnt/.../databases/prod/redis/ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ DEV (dev-portainer) │
│ 192.168.1.51 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Redis DEV (Standalone) │ │
│ │ Port : 6379 │ │
│ │ Memory : 512 Mo max │ │
│ │ Persistence : AOF + RDB │ │
│ │ Data : /mnt/.../databases/dev/redis/ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ PROD - HAUTE DISPONIBILITÉ │
│ │
│ ┌─────────────┐ réplication ┌─────────────┐ │
│ │ Master │ ─────────────────► │ Replica │ │
│ │ 192.168.1.11│ async │192.168.1.XX │ │
│ │ :6379 │ │ :6379 │ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ └──────────┬─────────────────────────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ Sentinel │ (failover automatique) │
│ │ :26379 │ │
│ └───────────────┘ │
└─────────────────────────────────────────────────────────────┘
Note : La config initiale est prête pour évoluer vers Master-Replica sans modification majeure.
| Option | Pour | Contre |
|---|---|---|
| Redis 7.4 (vanilla) | Léger, stable, bien documenté | Pas de modules avancés |
| Redis Stack | Modules (Search, JSON, TimeSeries) | Plus lourd (~500 Mo image) |
Recommandation : Redis 7.4 vanilla pour commencer. Passer à Redis Stack si besoin de modules.
| Mode | Config | Usage |
|---|---|---|
| AOF | appendonly yes, appendfsync everysec |
Durabilité (queues BullMQ) |
| RDB | Snapshots périodiques | Backups, restauration rapide |
# RDB : snapshots automatiques
save 900 1 # 1 changement en 15 min
save 300 10 # 10 changements en 5 min
save 60 10000 # 10000 changements en 1 min
# AOF : append-only file
appendonly yes
appendfsync everysec
| Env | Limite | Eviction Policy |
|---|---|---|
| PROD | 1 Go | allkeys-lru |
| DEV | 512 Mo | allkeys-lru |
Note : allkeys-lru = supprime les clés les moins récemment utilisées si mémoire pleine.
| Paramètre | PROD | DEV |
|---|---|---|
| Password | @REDIS_PROD_PASSWORD |
@REDIS_DEV_PASSWORD |
| Bind | 0.0.0.0 |
0.0.0.0 |
| Protected mode | no (password requis) |
no |
| TLS | Non (réseau interne) | Non |
/mnt/stock_36to/data/33800-stack/docker/stacks/redis-prod/redis-prod/
├── docker-compose.yml
├── redis.conf
└── .env
/mnt/stock_36to/data/33800-stack/docker/stacks/redis-dev/redis-dev/
├── docker-compose.yml
├── redis.conf
└── .env
version: '3.8'
services:
redis:
image: redis:7.4-alpine
container_name: redis-prod
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
- ./redis.conf:/usr/local/etc/redis/redis.conf:ro
command: redis-server /usr/local/etc/redis/redis.conf
environment:
- TZ=Europe/Paris
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 30s
timeout: 10s
retries: 3
networks:
- redis-net
volumes:
redis-data:
driver: local
driver_opts:
type: none
o: bind
device: /mnt/stock_36to/data/33800-stack/databases/prod/redis
networks:
redis-net:
driver: bridge
# =============================================================================
# NETWORK
# =============================================================================
bind 0.0.0.0
port 6379
protected-mode no
# =============================================================================
# SECURITY
# =============================================================================
requirepass ${REDIS_PASSWORD}
# Password pour la réplication (même que requirepass pour simplicité)
# Les replicas utilisent ce password pour se connecter au master
masterauth ${REDIS_PASSWORD}
# =============================================================================
# MEMORY
# =============================================================================
maxmemory 1gb
maxmemory-policy allkeys-lru
# =============================================================================
# PERSISTENCE - RDB (snapshots)
# =============================================================================
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /data
# =============================================================================
# PERSISTENCE - AOF (append-only file)
# =============================================================================
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# =============================================================================
# REPLICATION - Prêt pour Master-Replica
# =============================================================================
# Annonce l'IP publique pour que les replicas puissent se connecter
replica-announce-ip 192.168.1.11
replica-announce-port 6379
# Comportement si le master est déconnecté (replica continue à servir les reads)
replica-serve-stale-data yes
replica-read-only yes
# Synchronisation disque après réplication (sécurité)
repl-diskless-sync no
repl-diskless-sync-delay 5
# Ping du replica vers master
repl-ping-replica-period 10
repl-timeout 60
# Backlog pour la resynchronisation partielle
repl-backlog-size 1mb
repl-backlog-ttl 3600
# =============================================================================
# POUR ACTIVER LE MODE REPLICA (décommenter sur le replica)
# =============================================================================
# replicaof 192.168.1.11 6379
# =============================================================================
# LOGGING
# =============================================================================
loglevel notice
logfile ""
# =============================================================================
# PERFORMANCE
# =============================================================================
tcp-keepalive 300
timeout 0
tcp-backlog 511
# Limite clients simultanés
maxclients 10000
/mnt/stock_36to/data/33800-stack/docker/secrets/prod.env# Redis PROD
REDIS_PROD_HOST=192.168.1.11
REDIS_PROD_PORT=6379
REDIS_PROD_PASSWORD=<générer mot de passe fort>
REDIS_PROD_URL=redis://:${REDIS_PROD_PASSWORD}@192.168.1.11:6379
/mnt/stock_36to/data/33800-stack/docker/secrets/dev.env# Redis DEV
REDIS_DEV_HOST=192.168.1.51
REDIS_DEV_PORT=6379
REDIS_DEV_PASSWORD=<générer mot de passe différent>
REDIS_DEV_URL=redis://:${REDIS_DEV_PASSWORD}@192.168.1.51:6379
Ajouter Redis Exporter :
redis-exporter:
image: oliver006/redis_exporter:latest
container_name: redis-exporter-prod
restart: unless-stopped
ports:
- "9121:9121"
environment:
- REDIS_ADDR=redis://redis-prod:6379
- REDIS_PASSWORD=${REDIS_PASSWORD}
networks:
- redis-net
| Métrique | Seuil alerte |
|---|---|
redis_memory_used_bytes |
> 800 Mo (80%) |
redis_connected_clients |
> 100 |
redis_blocked_clients |
> 10 |
redis_commands_processed_total |
Baseline |
redis_keyspace_hits_total / misses |
Hit ratio < 80% |
#!/bin/bash
# /mnt/stock_36to/data/33800-stack/scripts/redis/backup-redis.sh
DATE=$(date +%Y-%m-%d)
BACKUP_DIR="/mnt/stock_36to/data/33800-stack/backups/redis"
# PROD
docker exec redis-prod redis-cli -a "$REDIS_PROD_PASSWORD" BGSAVE
sleep 5
cp /mnt/stock_36to/data/33800-stack/databases/prod/redis/dump.rdb \
"$BACKUP_DIR/prod/dump-$DATE.rdb"
# Rotation : garder 7 jours
find "$BACKUP_DIR/prod" -name "dump-*.rdb" -mtime +7 -delete
# Backup quotidien à 3h du matin
0 3 * * * /mnt/stock_36to/data/33800-stack/scripts/redis/backup-redis.sh
import Redis from 'ioredis';
const redis = new Redis({
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD,
maxRetriesPerRequest: 3,
retryDelayOnFailover: 100,
});
import { Queue, Worker } from 'bullmq';
const connection = {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT || '6379'),
password: process.env.REDIS_PASSWORD,
};
const emailQueue = new Queue('emails', { connection });
Sur une nouvelle machine (ex: 192.168.1.XX), créer redis-replica.conf :
# Copier redis.conf du master puis ajouter :
replicaof 192.168.1.11 6379
replica-announce-ip 192.168.1.XX
replica-announce-port 6379
sentinel.conf :
sentinel monitor redis-prod 192.168.1.11 6379 2
sentinel auth-pass redis-prod ${REDIS_PASSWORD}
sentinel down-after-milliseconds redis-prod 5000
sentinel failover-timeout redis-prod 60000
sentinel parallel-syncs redis-prod 1
redis-sentinel:
image: redis:7.4-alpine
container_name: redis-sentinel
command: redis-sentinel /etc/redis/sentinel.conf
volumes:
- ./sentinel.conf:/etc/redis/sentinel.conf
ports:
- "26379:26379"
import Redis from 'ioredis';
const redis = new Redis({
sentinels: [
{ host: '192.168.1.11', port: 26379 },
{ host: '192.168.1.XX', port: 26379 },
],
name: 'redis-prod',
password: process.env.REDIS_PASSWORD,
});
| Question | Choix |
|---|---|
| Version | Redis 7.4 (léger) |
| Mémoire PROD | 1 Go |
| Réplication | Standalone → compatible Master-Replica |
| Accès | Réseau local uniquement |
| Ressource | PROD | DEV |
|---|---|---|
| RAM | ~100-200 Mo (au départ) | ~50-100 Mo |
| CPU | Négligeable | Négligeable |
| Disque | ~100 Mo (données + AOF) | ~50 Mo |
| Env | URL interne | Port |
|---|---|---|
| PROD | redis-prod.local ou 192.168.1.11 |
6379 |
| DEV | redis-dev.local ou 192.168.1.51 |
6379 |
Note : Redis n'a pas besoin de reverse proxy Nginx (protocole binaire, pas HTTP).
Statut : En attente de validation des choix
Prochaine étape : Valider les options ci-dessus, puis déployer Redis PROD