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 services. Dans l'écosystème Go (Golang), le développeur a accès à la fois à des systèmes de cache externes (Redis, Memcached) et à des solutions intégrées comme sync.Map ou les bibliothèques bigcache et freecache. Dans cet article, nous analyserons les avantages et les inconvénients de chaque approche, fournirons des exemples de code et vous aiderons à choisir l'outil optimal pour votre projet.
1. Mise en cache intégrée : sync.Map et map avec mutex
Go propose des primitives de base pour créer un cache directement dans la mémoire de l'application. La méthode la plus simple consiste à utiliser un map classique avec un mutex pour la sécurité des threads.
Exemple : un cache simple thread-safe
package main
import ( "fmt" "sync" "time")
type Cache struct { mu sync.RWMutex items map[string]interface{}}
func NewCache() *Cache { return &Cache{ items: make(map[string]interface{}), }}
func (c *Cache) Set(key string, value interface{}) { c.mu.Lock() defer c.mu.Unlock() c.items[key] = value}
func (c *Cache) Get(key string) (interface{}, bool) { c.mu.RLock() defer c.mu.RUnlock() val, ok := c.items[key] return val, ok}
func main() { cache := NewCache() cache.Set("user:1", "Alice") val, _ := cache.Get("user:1") fmt.Println(val) // Alice}Pour des scénarios plus complexes, Go fournit sync.Map — une carte concurrente optimisée, mieux adaptée aux cas où les clés sont écrites une fois et lues plusieurs fois.
Quand utiliser la mise en cache intégrée ?
- Micro-caching (pour la durée d'une requête ou d'une session).
- Applications singleton sans architecture distribuée.
- Simplicité — pas besoin de déployer des services externes.
Inconvénients : absence d'invalidation automatique, taille limitée (dépend de la mémoire de l'application), pas de persistance.
2. BigCache et FreeCache : solutions in-memory légères
Les bibliothèques bigcache et freecache résolvent le problème de la mémoire limitée et du GC (garbage collector). Elles utilisent des tampons pré-alloués et minimisent la charge sur le garbage collector de Go.
Exemple avec BigCache
package main
import ( "fmt" "github.com/allegro/bigcache/v3" "time")
func main() { cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute)) cache.Set("mykey", []byte("myvalue")) val, _ := cache.Get("mykey") fmt.Println(string(val)) // myvalue}Exemple avec FreeCache
package main
import ( "fmt" "github.com/coocood/freecache")
func main() { cache := freecache.NewCache(100 * 1024) // 100 KB cache.Set([]byte("key"), []byte("value"), 60) // TTL 60 sec val, _ := cache.Get([]byte("key")) fmt.Println(string(val)) // value}Les deux bibliothèques prennent en charge le TTL (time-to-live) et la suppression automatique des anciennes entrées. BigCache est meilleur pour les grands volumes de données (centaines de gigaoctets), FreeCache pour les scénarios avec des opérations fréquentes d'écriture/lecture.
3. Redis : mise en cache distribuée pour la production
Redis est le choix le plus populaire pour la mise en cache dans les projets Go. Il fonctionne comme un serveur séparé, prend en charge des structures de données complexes, la persistance et le clustering.
Connexion à Redis en Go
package main
import ( "context" "fmt" "github.com/redis/go-redis/v9")
func main() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", DB: