Mise en cache en Go : Redis, Memcached et solutions intégrées
La mise en cache est l'un des outils clés pour améliorer les performances des applications web et des microservices. En Go (Golang), il existe plusieurs approches : des structures de données intégrées simples aux systèmes distribués puissants comme Redis et Memcached. Dans cet article, nous examinerons les principales options de mise en cache, leurs avantages, leurs inconvénients et fournirons des exemples de code pratiques.
Pourquoi la mise en cache en Go est-elle nécessaire ?
Go est réputé pour sa vitesse et son efficacité, mais même dans ce langage, on rencontre souvent des goulots d'étranglement : requêtes lentes à la base de données, API externes ou calculs lourds. La mise en cache permet de :
- Réduire la charge sur la base de données et les services externes.
- Diminuer le temps de réponse de l'API (latence).
- Économiser les ressources du serveur (CPU, mémoire).
- Améliorer la tolérance aux pannes lors de défaillances temporaires.
Le choix de la solution dépend de l'architecture de l'application : monolithe ou microservices, exigences de cohérence des données, volume du cache et budget.
Mise en cache intégrée en Go
Pour les scénarios simples (par exemple, mise en cache de données au sein d'un seul processus), les outils intégrés de Go conviennent. Ils ne nécessitent pas l'installation de services externes et sont idéaux pour les petites applications.
1. sync.Map
sync.Map est une map thread-safe de la bibliothèque standard de Go. Elle convient pour la mise en cache qui est rarement mise à jour et souvent lue. Exemple :
package main
import ( "fmt" "sync")
func main() { var cache sync.Map
// Sauvegarder les données cache.Store("user_1", "Alice") cache.Store("user_2", "Bob")
// Lire les données if val, ok := cache.Load("user_1"); ok { fmt.Println("Trouvé :", val) }
// Supprimer cache.Delete("user_2")}Avantages : simplicité, aucune dépendance externe, thread-safe. Inconvénients : pas de TTL (durée de vie), pas de nettoyage automatique, limité à un seul processus.
2. Package go-cache
La bibliothèque populaire github.com/patrickmn/go-cache ajoute la prise en charge du TTL et du nettoyage automatique. Exemple :
package main
import ( "fmt" "time" "github.com/patrickmn/go-cache")
func main() { // Créer un cache avec une durée de vie de 5 minutes et un nettoyage toutes les 10 minutes c := cache.New(5*time.Minute, 10*time.Minute)
// Sauvegarder avec TTL c.Set("session_token", "abc123", cache.DefaultExpiration)
// Récupérer token, found := c.Get("session_token") if found { fmt.Println("Token :", token) }
// Supprimer c.Delete("session_token")}Avantages : TTL, simplicité d'intégration, nettoyage automatique. Inconvénients : les données sont stockées dans la mémoire d'un seul processus, ne convient pas aux systèmes distribués.
Redis : mise en cache distribuée pour Go
Redis est la solution de mise en cache la plus populaire en Go. Il fonctionne comme un serveur séparé, prend en charge des structures de données complexes (chaînes, hachages, listes, ensembles) et bénéficie d'un excellent support en Go via le driver go-redis.
Connexion et opérations de base
package main
import ( "context" "fmt" "github.com/redis/go-redis/v9")
func main() { ctx := context.Background()
// Connexion à Redis rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // sans mot de passe DB: 0, })
// Sauvegarder une chaîne avec TTL (1 heure) err := rdb.Set(ctx, "key", "value", 3600*time.Second).Err() if err != nil { panic(err) }
// Lire val, err := rdb.Get(ctx, "key").Result() if err != nil { fmt.Println("Clé non trouvée") } else { fmt.Println("Valeur :", val) }
// Supprimer rdb.Del(ctx, "key")}