Mise en cache en Go (Golang) : Redis et outils alternatifs

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Mise en cache en Go (Golang) : Redis et autres outils



La mise en cache est l'un des mécanismes clés pour optimiser les performances des applications web et des microservices. Dans l'écosystème Go (Golang), il existe de nombreuses bibliothèques pour implémenter la mise en cache, allant de simples solutions en mémoire à des systèmes distribués basés sur Redis. Dans cet article, nous allons détailler trois approches principales : les structures de données intégrées (sync.Map), les bibliothèques en mémoire populaires (go-cache, freecache, bigcache) et l'intégration avec Redis.



1. Outils intégrés : sync.Map



Go fournit une map thread-safe — sync.Map. Elle convient pour une mise en cache simple avec un faible volume de données et des mises à jour peu fréquentes. Cependant, ses performances sous forte charge sont inférieures à celles des bibliothèques spécialisées.



Exemple d'utilisation de sync.Map :

package main

import ( "fmt" "sync" "time")

func main() { var cache sync.Map

// Écriture cache.Store("user:42", map[string]interface{}{ "name": "Alice", "age": 30, })

// Lecture avec vérification if val, ok := cache.Load("user:42"); ok { fmt.Println("Cache trouvé :", val) }

// Suppression cache.Delete("user:42")

// Mise en cache avec TTL (à implémenter manuellement) cache.Store("session:abc", time.Now().Unix())}


Inconvénients : absence de TTL automatique, ensemble d'opérations limité, problèmes de performance possibles en cas d'écritures fréquentes.



2. Bibliothèques en mémoire



Pour des scénarios plus complexes, utilisez des bibliothèques spécialisées. Examinons trois bibliothèques populaires :



2.1 go-cache

Bibliothèque simple avec support du TTL. Idéale pour les petits projets.

import "github.com/patrickmn/go-cache"

func main() { c := cache.New(5*time.Minute, 10*time.Minute) // TTL par défaut, intervalle de nettoyage

c.Set("key", "value", cache.DefaultExpiration) val, found := c.Get("key") if found { fmt.Println(val) }}


2.2 freecache

Bibliothèque avec une taille mémoire fixe (pas de surcharge GC). Supporte le TTL et offre des performances élevées.

import "github.com/coocood/freecache"

func main() { cache := freecache.NewCache(100 * 1024 * 1024) // 100 Mo

cache.Set([]byte("mykey"), []byte("myvalue"), 60) // TTL 60 sec val, err := cache.Get([]byte("mykey")) if err == nil { fmt.Println(string(val)) }}


2.3 bigcache

Optimisée pour le stockage de grands volumes de données sans pauses GC. Fonctionne avec des données sérialisées.

import "github.com/allegro/bigcache/v3"

func main() { cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))

cache.Set("key", []byte("value")) val, _ := cache.Get("key") fmt.Println(string(val))}


3. Redis : mise en cache distribuée



Pour les systèmes distribués et les microservices, Redis reste le standard de facto. En Go, utilisez la bibliothèque go-redis/redis (v9+).



Connexion et opérations de base :

import (    "context"    "fmt"    "github.com/redis/go-redis/v9")

func main() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", DB: 0, })

// Définition d'une valeur avec TTL err := rdb.Set(ctx, "user:42", `{"name":"Bob"}`, 10*time.Minute).Err() if err != nil { panic(err) }

// Lecture val, err := rdb.Get(ctx, "user:42").Result() if err == redis.Nil { fmt.Println("Cache non trouvé") } else if err != nil { panic(err) } else { fmt.Println("Valeur :", val) }}


Fonctionnalités avancées de Redis en Go :

  • Pipeline : regroupez plusieurs commandes pour réduire la latence réseau.
  • Transactions : utilisez MULTI/EXEC pour des opérations atomiques.
  • Pub/Sub : implémentez des notifications en temps réel.
  • Redis Cluster : distribution automatique des données sur plusieurs nœuds.


4. Mise en cache de groupe



Pour les applications avec des charges de lecture élevées, la mise en cache de groupe (groupcache) évite les écrasements de cache (cache stampede). La bibliothèque groupcache de Google offre :

  • Distribution décentralisée du cache entre plusieurs nœuds.
  • Protection contre les écrasements de cache grâce à un mécanisme de déduplication des requêtes.
  • Interface simple pour la récupération des données.


Exemple d'utilisation de groupcache :

import (    "fmt"    "github.com/golang/groupcache")

func main() { peers := groupcache.NewHTTPPool("http://localhost:8080")

cache := groupcache.NewGroup("users", 64<<20, groupcache.GetterFunc( func(ctx groupcache.Context, key string, dest groupcache.Sink) error { // Chargement des données depuis la source (base de données, API, etc.) dest.SetString("Valeur pour " + key) return nil }, ))

var result string err := cache.Get(nil, "user:42", groupcache.StringSink(&result)) if err != nil { fmt.Println("Erreur :", err) } else { fmt.Println("Résultat :", result) }}


5. Comparaison des performances



Outil Débit (ops/sec) Latence (μs) Utilisation mémoire Distribution
sync.Map ~5 000 000 ~200 Élevée (GC) Non
go-cache ~3 000 000 ~300 Moyenne Non
freecache ~10 000 000 ~100 Faible (pas de GC) Non
bigcache ~8 000 000 ~150 Faible (pas de GC) Non
Redis (local) ~100 000 ~10 000 Faible Oui
groupcache ~2 000 000 ~500 Moyenne Oui


6. Recommandations



  1. Pour les petits projets : utilisez go-cache ou sync.Map.
  2. Pour des charges élevées avec des données volumineuses : freecache ou bigcache.
  3. Pour les systèmes distribués : Redis ou groupcache.
  4. Pour la protection contre les écrasements de cache : groupcache.


Conclusion



Le choix de l'outil de mise en cache dépend des exigences spécifiques de votre projet : volume de données, exigences de latence, besoin de distribution et budget mémoire. En Go, vous disposez d'un large éventail d'outils — des solutions intégrées simples aux systèmes distribués puissants. Expérimentez avec différentes bibliothèques et mesurez les performances dans votre contexte particulier.



Article original : PythonLib

Recommendations