Caching in Go: Redis, Memcached und integrierte Lösungen
Caching ist eines der wichtigsten Werkzeuge zur Leistungssteigerung von Webanwendungen und Diensten. Im Go-Ökosystem (Golang) stehen dem Entwickler sowohl externe Caching-Systeme (Redis, Memcached) als auch integrierte Lösungen wie sync.Map oder die Bibliotheken bigcache und freecache zur Verfügung. In diesem Artikel analysieren wir die Vor- und Nachteile jedes Ansatzes, geben Codebeispiele und helfen Ihnen, das optimale Werkzeug für Ihr Projekt auszuwählen.
1. Integriertes Caching: sync.Map und map mit Mutex
Go bietet grundlegende Primitive zum Erstellen eines Caches direkt im Arbeitsspeicher der Anwendung. Der einfachste Weg ist die Verwendung einer normalen map mit einem Mutex für die Thread-Sicherheit.
Beispiel: Einfacher thread-sicherer Cache
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}Für komplexere Szenarien bietet Go sync.Map – eine optimierte nebenläufige Map, die besser geeignet ist, wenn Schlüssel einmal geschrieben und viele Male gelesen werden.
Wann sollte man integriertes Caching verwenden?
- Micro-Caching (für die Dauer einer einzelnen Anfrage oder Sitzung).
- Singleton-Anwendungen ohne verteilte Architektur.
- Einfachheit – es müssen keine externen Dienste gestartet werden.
Nachteile: Fehlen einer automatischen Invalidierung, begrenzte Größe (abhängig vom Arbeitsspeicher der Anwendung), keine Persistenz.
2. BigCache und FreeCache: Leichtgewichtige In-Memory-Lösungen
Die Bibliotheken bigcache und freecache lösen das Problem des begrenzten Speichers und der GC (Garbage Collection). Sie verwenden vorab zugewiesene Puffer und minimieren die Belastung des Go-Garbage Collectors.
Beispiel mit 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}Beispiel mit 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 Sek. val, _ := cache.Get([]byte("key")) fmt.Println(string(val)) // value}Beide Bibliotheken unterstützen TTL (Time-To-Live) und das automatische Entfernen alter Einträge. BigCache ist besser für große Datenmengen (Hunderte Gigabyte), FreeCache für Szenarien mit häufigen Schreib-/Leseoperationen geeignet.
3. Redis: Verteiltes Caching für die Produktion
Redis ist die beliebteste Wahl für Caching in Go-Projekten. Es läuft als separater Server, unterstützt komplexe Datenstrukturen, Persistenz und Clustering.
Redis-Verbindung in 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: