Pourquoi Caching avec Express et Redis ?
Le caching est une technique essentielle en développement web pour améliorer les performances des applications. Au quotidien, un développeur peut avoir besoin de cache pour plusieurs raisons :
- Amélioration des performances : En stockant fréquemment les données en mémoire, le serveur peut accéder à ces données plus rapidement, réduisant ainsi la latence et l'utilisation des ressources.
- Charge aménagée sur les bases de données : Le caching évite les requêtes fréquentes aux bases de données, ce qui libère les ressources pour des opérations d'écriture et d'autres tâches importantes.
Un cas d'usage concret serait une application e-commerce où le catalogue des produits est consulté souvent. En utilisant un cache Redis, vous pouvez stocker la liste des produits en mémoire, et chaque fois qu'un utilisateur demande les produits, votre serveur peut récupérer cette information du cache plutôt que de la base de données.
Prerequis
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :
Connaissances :
- JavaScript ES6+
- Node.js
- Express.js
- Redis
- Bases de MySQL (pour le projet fil rouge)
Outils à installer :
npm install express redis mysql2
Concepts fondamentaux
Concept 1: Introduction au Caching avec Express et Redis
Le caching est un mécanisme qui permet d'entreposer des données dans une zone de stockage temporaire pour leur accès plus rapide à l'avenir. Avec Express.js, nous pouvons utiliser Redis, un système de base de données en mémoire, comme cache.
// Importation des modules nécessaires
const express = require('express');
const redis = require('redis');
// Création d'une application Express
const app = express();
app.use(express.json());
// Connexion à Redis
const client = redis.createClient({
url: 'redis://127.0.0.1:6379'
});
client.connect().then(() => {
console.log('Connected to Redis');
}).catch(err => {
console.error('Failed to connect to Redis', err);
});
Concept 2: Lire et écrire des données dans Redis
Pour lire et écrire des données dans Redis, nous utilisons les méthodes GET et SET.
// Écrire une valeur dans Redis
app.post('/set/:key/:value', async (req, res) => {
try {
await client.set(req.params.key, req.params.value);
res.send(`Value set for key ${req.params.key}`);
} catch (err) {
res.status(500).send(err.message);
}
});
// Lire une valeur dans Redis
app.get('/get/:key', async (req, res) => {
try {
const value = await client.get(req.params.key);
if (!value) {
return res.status(404).send('Key not found');
}
res.send(value);
} catch (err) {
res.status(500).send(err.message);
}
});
Mise en pratique : Projet fil rouge
Étape 1: Configuration de l'application Express et MySQL
Créez un nouveau projet avec la structure suivante :
mkdir express-redis-cache
cd express-redis-cache
npm init -y
npm install express redis mysql2
Créez les fichiers suivants :
app.js :
const express = require('express');
const redis = require('redis');
const mysql = require('mysql2');
const app = express();
app.use(express.json());
// Connexion à Redis
const client = redis.createClient({
url: 'redis://127.0.0.1:6379'
});
client.connect().then(() => {
console.log('Connected to Redis');
}).catch(err => {
console.error('Failed to connect to Redis', err);
});
// Connexion à MySQL
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'tasksdb'
});
connection.connect((err) => {
if (err) throw err;
console.log('Connected to MySQL');
});
routes/tasks.js :
const express = require('express');
const router = express.Router();
const connection = require('../config/db');
// Récupérer toutes les tâches
router.get('/tasks', async (req, res) => {
try {
const tasksKey = 'tasks';
const cachedTasks = await client.get(tasksKey);
if (cachedTasks) {
return res.send(JSON.parse(cachedTasks));
}
const [rows] = await connection.promise().query('SELECT * FROM tasks');
await client.setex(tasksKey, 3600, JSON.stringify(rows)); // Stocker les tâches pendant 1 heure
res.send(rows);
} catch (err) {
res.status(500).send(err.message);
}
});
module.exports = router;
config/db.js :
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'tasksdb'
});
module.exports = connection;
Étape 2: Création de la base de données MySQL
Créez une base de données et une table tasks :
CREATE DATABASE tasksdb;
USE tasksdb;
CREATE TABLE tasks (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT
);
Étape 3: Lancement de l'application
Ajoutez un script dans package.json :
"scripts": {
"start": "node app.js"
}
Lancez l'application :
npm start
Erreurs fréquentes et debugging
Erreur 1: Connexion échouée à Redis
Code incorrect :
const client = redis.createClient({
url: 'redis://localhost:6379'
});
Correction :
const client = redis.createClient({
url: 'redis://127.0.0.1:6379'
});
Erreur 2: Connexion échouée à MySQL
Code incorrect :
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'password',
database: 'tasksdb'
});
Correction :
Vérifiez que le nom de l'utilisateur, du mot de passe et du nom de la base de données sont corrects.
Erreur 3: Récupération de données Redis échouée
Code incorrect :
const cachedTasks = await client.get(tasksKey);
if (!cachedTasks) {
return res.send('No tasks found');
}
Correction :
const cachedTasks = await client.get(tasksKey);
if (!cachedTasks) {
return res.status(404).send('No tasks found');
}
Pour aller plus loin
Piste 1: Utiliser des sérializeurs personnalisés
Vous pouvez utiliser des sérializeurs personnalisés pour gérer les données complexes.
const serialize = (data) => JSON.stringify(data);
const deserialize = (data) => JSON.parse(data);
client.setex(tasksKey, 3600, serialize(rows));
const cachedTasks = await client.get(tasksKey);
if (cachedTasks) {
const tasks = deserialize(cachedTasks);
res.send(tasks);
}
Piste 2: Utiliser des expirations dynamiques
Vous pouvez utiliser des expirations dynamiques en fonction du contenu des données.
const expirationTime = calculateExpiryTime(rows); // Fonction personnalisée pour calculer l'expiration
await client.setex(tasksKey, expirationTime, JSON.stringify(rows));
Piste 3: Utiliser des clusters Redis
Pour gérer une grande charge de travail, vous pouvez utiliser des clusters Redis.
npm install ioredis
app.js :
const IORedis = require('ioredis');
const redisCluster = new IORedis.Cluster([
{ host: '127.0.0.1', port: 6379 },
{ host: '127.0.0.1', port: 6380 }
]);
Défi pratique
Créez un CLI tool qui permet d'ajouter et de récupérer des tâches en utilisant le cache Redis.
Conclusion
Ce tutoriel vous a permis de comprendre comment utiliser le caching avec Express.js et Redis pour améliorer les performances de votre application. En suivant les étapes et en réalisant le projet fil rouge, vous avez pu mettre en pratique ces concepts de manière complète. N'oubliez pas que le caching est un sujet vaste et continu d'apprendre, il existe de nombreuses façons de l'optimiser et de l'intégrer dans vos projets.