Pourquoi Caching avec Go et Redis ?
Contexte réel : En tant que développeur, vous avez probablement rencontré des problèmes de performances liés à la base de données lorsqu'elle est surchargée par une grande quantité de requêtes en lecture ou d'écriture. Le caching est une technique qui permet de stocker une copie temporaire des données récemment lues ou écrites dans le cache, pour éviter de les récupérer à nouveau depuis la base de données. Cela améliore considérablement les performances en réduisant le temps d'accès aux données.
Un cas d'usage concret : Imaginez que vous développiez une application e-commerce qui affiche des produits populaires. Chaque fois qu'un utilisateur visite cette page, votre application effectue une requête à la base de données pour récupérer les informations des produits les plus populaires. Si ce n'est pas stocké dans le cache, chaque visitant de la page aura besoin d'effectuer cette requête, ce qui entraîne une grande charge sur la base de données et peut entraîner un temps de réponse lent.
Prerequis
Connaissances nécessaires :
- Go (version >= 1.16)
- Redis (version >= 6.2)
Outils à installer :
- Go (https://golang.org/dl/)
- Redis (https://redis.io/download)
Concepts fondamentaux
1. Connexion à Redis avec Go
Redis expose une API en Go qui permet de se connecter et d'interagir avec le serveur Redis.
Code :
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379", // Adresse du serveur Redis
Password: "", // Mot de passe (si nécessaire)
DB: 0, // Numéro de la base de données
})
pong, err := client.Ping(ctx).Result()
if err != nil {
panic(err)
}
fmt.Println("Connected to Redis:", pong)
}
2. Stockage et récupération de données dans le cache
Vous pouvez stocker des valeurs dans le cache en utilisant la commande Set et les récupérer avec la commande Get.
Code :
func storeAndRetrieveData(client *redis.Client) {
ctx := context.Background()
err := client.Set(ctx, "user:1:name", "John Doe", 0).Err() // Stocker un élément dans le cache
if err != nil {
panic(err)
}
name, err := client.Get(ctx, "user:1:name").Result() // Récupérer l'élément du cache
if err != nil {
panic(err)
}
fmt.Println("Retrieved name:", name)
}
3. Expiration des données dans le cache
Vous pouvez définir une durée d'expiration pour chaque élément stocké dans le cache.
Code :
func storeDataWithExpiration(client *redis.Client) {
ctx := context.Background()
err := client.Set(ctx, "user:1:name", "John Doe", 60*time.Second).Err() // Stocker un élément avec une durée d'expiration de 60 secondes
if err != nil {
panic(err)
}
time.Sleep(65 * time.Second) // Attente de plus de la durée d'expiration
name, err := client.Get(ctx, "user:1:name").Result()
if err == redis.Nil {
fmt.Println("Key does not exist in the cache")
} else if err != nil {
panic(err)
}
}
Mise en pratique : projet fil rouge
Étape 1 : Initialisation du projet
Créer un nouveau dossier pour votre projet et initialiser un nouveau projet Go.
mkdir go-redis-cache-example
cd go-redis-cache-example
go mod init go-redis-cache-example
Étape 2 : Installation de la bibliothèque Redis
Ajoutez la dépendance Redis à votre fichier go.mod.
Code :
require (
"github.com/go-redis/redis/v8" v8.10.3
)
Ensuite, téléchargez les dépendances.
go mod tidy
Étape 3 : Connexion à Redis
Créez un fichier main.go et ajoutez le code pour se connecter à Redis.
Code :
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
)
func main() {
ctx := context.Background()
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
pong, err := client.Ping(ctx).Result()
if err != nil {
panic(err)
}
fmt.Println("Connected to Redis:", pong)
storeAndRetrieveData(client)
storeDataWithExpiration(client)
}
Étape 4 : Stockage et récupération de données
Ajoutez la fonction storeAndRetrieveData pour stocker et récupérer des données dans le cache.
Code :
func storeAndRetrieveData(client *redis.Client) {
ctx := context.Background()
err := client.Set(ctx, "user:1:name", "John Doe", 0).Err()
if err != nil {
panic(err)
}
name, err := client.Get(ctx, "user:1:name").Result()
if err != nil {
panic(err)
}
fmt.Println("Retrieved name:", name)
}
Étape 5 : Expiration des données
Ajoutez la fonction storeDataWithExpiration pour stocker des données avec une durée d'expiration.
Code :
func storeDataWithExpiration(client *redis.Client) {
ctx := context.Background()
err := client.Set(ctx, "user:1:name", "John Doe", 60*time.Second).Err()
if err != nil {
panic(err)
}
time.Sleep(65 * time.Second)
name, err := client.Get(ctx, "user:1:name").Result()
if err == redis.Nil {
fmt.Println("Key does not exist in the cache")
} else if err != nil {
panic(err)
}
}
Étape 6 : Exécution du projet
Exécutez votre programme Go pour vous assurer que tout fonctionne correctement.
go run main.go
Erreurs fréquentes et debugging
1. Connexion échoue avec une erreur de port
Code incorrect :
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
Erreur : redis: no address given
Correction :
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
2. Récupération de données non existantes
Code incorrect :
name, err := client.Get(ctx, "user:1:name").Result()
if err != nil {
fmt.Println("Key does not exist in the cache")
}
Erreur : redis: nil
Correction :
name, err := client.Get(ctx, "user:1:name").Result()
if err == redis.Nil {
fmt.Println("Key does not exist in the cache")
} else if err != nil {
panic(err)
}
3. Stockage de données avec une erreur d'expiration
Code incorrect :
err := client.Set(ctx, "user:1:name", "John Doe", -1).Err()
if err != nil {
panic(err)
}
Erreur : invalid expiration duration: -1
Correction :
err := client.Set(ctx, "user:1:name", "John Doe", 0).Err() // Utiliser 0 pour désactiver l'expiration
if err != nil {
panic(err)
}
Pour aller plus loin
1. Multi-clients Redis
Utilisez plusieurs clients Redis pour gérer différents ensembles de données.
Liens :
2. Transactions Redis
Exécutez des transactions atomiques sur le cache Redis.
Liens :
3. Pub/Sub avec Redis
Utilisez la fonctionnalité Pub/Sub de Redis pour publier et recevoir des messages.
Liens :
Défi pratique
Implémentez un simple cache en mémoire pour une application web utilisant Go. Le cache devrait stocker les résultats d'appels API fréquents afin de réduire le temps de réponse et la charge sur l'API.
Liens :