Cache em Go: Redis, Memcached e soluções embutidas
Cache é uma das ferramentas chave para melhorar o desempenho de aplicações web e serviços. No ecossistema Go (Golang), o desenvolvedor tem acesso tanto a sistemas de cache externos (Redis, Memcached) quanto a soluções embutidas como sync.Map ou as bibliotecas bigcache e freecache. Neste artigo, analisaremos os prós e contras de cada abordagem, forneceremos exemplos de código e ajudaremos você a escolher a ferramenta ideal para o seu projeto.
1. Cache embutido: sync.Map e map com mutex
Go oferece primitivas básicas para criar cache diretamente na memória da aplicação. A maneira mais simples é usar um map comum com um mutex para segurança em concorrência.
Exemplo: cache simples 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}Para cenários mais complexos, Go fornece sync.Map — um mapa concorrente otimizado, mais adequado para casos onde as chaves são escritas uma vez e lidas muitas vezes.
Quando usar cache embutido?
- Micro-cache (durante uma única requisição ou sessão).
- Aplicações singleton sem arquitetura distribuída.
- Simplicidade — não é necessário configurar serviços externos.
Desvantagens: ausência de invalidação automática, tamanho limitado (depende da memória da aplicação), sem persistência.
2. BigCache e FreeCache: soluções leves in-memory
As bibliotecas bigcache e freecache resolvem o problema de memória limitada e GC (coleta de lixo). Elas usam buffers pré-alocados e minimizam a carga no garbage collector do Go.
Exemplo com 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}Exemplo com 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 seg val, _ := cache.Get([]byte("key")) fmt.Println(string(val)) // value}Ambas as bibliotecas suportam TTL (tempo de vida) e remoção automática de entradas antigas. BigCache é melhor para grandes volumes de dados (centenas de gigabytes), FreeCache para cenários com operações frequentes de escrita/leitura.
3. Redis: cache distribuído para produção
Redis é a escolha mais popular para cache em projetos Go. Ele funciona como um servidor separado, suporta estruturas de dados complexas, persistência e clusterização.
Conectando Redis em 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: 0, })
err := rdb.Set(ctx, "key", "value", 0).Err() if err != nil { panic(err) }
val, err := rdb.Get(ctx, "key").Result() if err != nil { panic(err) } fmt.Println("key", val)}Redis é ideal para aplicações distribuídas, cache compartilhado entre múltiplas instâncias e cenários que exigem recursos avançados como filas ou pub/sub.
```