Cache em Go (Golang): Redis e outras soluções
Cache é uma das ferramentas-chave para melhorar o desempenho de aplicações Go. Ele permite reduzir o tempo de resposta, diminuir a carga em bancos de dados e APIs externas. Neste artigo, abordaremos as principais abordagens de cache em Go: uso do Redis como armazenamento externo, cache in-memory embutido e cache em grupo com a biblioteca groupcache.
1. Por que o cache é necessário em Go?
Go é uma linguagem voltada para alto desempenho, mas mesmo as consultas mais rápidas ao BD ou serviços externos podem se tornar um gargalo. O cache ajuda a:
- Reduzir latências em consultas repetitivas.
- Diminuir a carga em bancos de dados e APIs de terceiros.
- Aumentar a capacidade de processamento do servidor.
- Suavizar picos de carga.
2. Redis — cache distribuído
Redis é a solução mais popular para cache externo em Go. Ele funciona como um armazenamento in-memory com suporte a TTL, persistência e estruturas de dados complexas.
Conectando Redis em Go
Para trabalhar com Redis em Go, a biblioteca mais usada é go-redis. Instalação:
go get github.com/redis/go-redis/v9Exemplo: cache simples com TTL
package main
import ( "context" "fmt" "time" "github.com/redis/go-redis/v9")
var ctx = context.Background()
func main() { rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", })
// Define valor com TTL de 10 segundos err := rdb.Set(ctx, "user:42", `{"name":"Alice"}`, 10*time.Second).Err() if err != nil { panic(err) }
// Obtém valor val, err := rdb.Get(ctx, "user:42").Result() if err != nil { fmt.Println("Cache miss") } else { fmt.Println("Cache hit:", val) }}Estratégias de invalidação de cache no Redis
- TTL (Time To Live) — remoção automática após expiração.
- Invalidação preguiçosa (Lazy) — limpeza do cache ao atualizar dados.
- Remoção por chave — chamada
DELpara uma chave específica. - Padrão "Cache-Aside" — a aplicação gerencia o cache: primeiro verifica o Redis, em caso de miss carrega do BD e salva no cache.
3. Cache in-memory em Go
Para cache local sem dependências externas, podem ser usadas estruturas nativas do Go ou bibliotecas especializadas.
Cache in-memory simples com sync.Map
package main
import ( "fmt" "sync" "time")
type CacheItem struct { Value interface{} Expiration int64}
type Cache struct { items sync.Map}
func (c *Cache) Set(key string, value interface{}, ttl time.Duration) { c.items.Store(key, CacheItem{ Value: value, Expiration: time.Now().Add(ttl).UnixNano(), })}
func (c *Cache) Get(key string) (interface{}, bool) { item, found := c.items.Load(key) if !found { return nil, false } cacheItem := item.(CacheItem) if time.Now().UnixNano() > cacheItem.Expiration { c.items.Delete(key) return nil, false } return cacheItem.Value, true}
func main() { cache := &Cache{} cache.Set("key1", "value1", 5*time.Second) val, ok := cache.Get("key1") if ok { fmt.Println("Encontrado:", val) }}Biblioteca freecache
freecache é uma biblioteca in-memory de alto desempenho com suporte a TTL e baixo consumo de memória. Instalação:
go get github.com/coocood/freecachecache := freecache.NewCache(100 * 1024 * 1024) // 100 MBcache.Set([]by