Introducción: Por qué el caching es crítico para las aplicaciones Go
En el desarrollo web moderno, la velocidad de respuesta de una aplicación afecta directamente la experiencia del usuario y la conversión. El lenguaje Go (Golang) es conocido por su rendimiento, pero incluso la aplicación más optimizada puede encontrar cuellos de botella al trabajar con bases de datos o APIs externas. Aquí es donde el caching viene al rescate.
El caching es el almacenamiento temporal de datos solicitados con frecuencia en un almacenamiento rápido. En el ecosistema de Go, existen tres enfoques principales:
- Soluciones integradas (sync.Map, map + mutex) — para pequeños volúmenes de datos dentro de un solo proceso.
- Memcached — caché distribuida en memoria, simple y rápida.
- Redis — almacenamiento avanzado con soporte para estructuras de datos, persistencia y clustering.
En este artículo, analizaremos cada opción con ejemplos prácticos en Go, compararemos su rendimiento y daremos recomendaciones para elegir.
Caching integrado en Go: sync.Map y mapas concurrentes
Para escenarios simples, donde el caché no necesita ser distribuido, Go ofrece herramientas estándar. La opción más popular es sync.Map, introducida en Go 1.9.
Ejemplo: sync.Map para almacenar en caché resultados de API
package main
import ( "fmt" "sync" "time")
type Cache struct { data sync.Map}
func (c *Cache) Get(key string) (interface{}, bool) { return c.data.Load(key)}
func (c *Cache) Set(key string, value interface{}, ttl time.Duration) { c.data.Store(key, value) time.AfterFunc(ttl, func() { c.data.Delete(key) })}
func main() { cache := &Cache{} cache.Set("user_42", "Alice", 5*time.Second)
if val, ok := cache.Get("user_42"); ok { fmt.Println("El caché contiene:", val) }}Ventajas: cero dependencias, seguridad en concurrencia, simplicidad.
Desventajas: sin desalojo automático (excepto TTL mediante soluciones improvisadas), sin distribución, rendimiento limitado bajo alta contención.
Para escenarios más complejos, use bibliotecas como go-cache o bigcache, que ofrecen TTL, desalojo LFU/LRU y baja latencia.
Memcached en Go: caché distribuido ligero y rápido
Memcached es un sistema de caching distribuido en memoria. Es ideal para almacenar pares simples "clave-valor" de tamaño pequeño (hasta 1 MB).
Conexión a Memcached desde Go
Para trabajar con Memcached, use la biblioteca github.com/bradfitz/gomemcache.
package main
import ( "fmt" "github.com/bradfitz/gomemcache/memcache")
func main() { mc := memcache.New("localhost:11211")
// Escritura en caché err := mc.Set(&memcache.Item{ Key: "user_100", Value: []byte(`{"name":"Bob","age":30}`), Expiration: 300, // 5 minutos }) if err != nil { panic(err) }
// Lectura desde caché item, err := mc.Get("user_100") if err == nil { fmt.Printf("Datos: %s", item.Value) } else { fmt.Println("Fallo de caché") }}Cuándo elegir Memcached:
- Necesita un almacenamiento simple de clave-valor.
- El tamaño de los objetos no supera 1 MB.
- No se requiere persistencia ni estructuras de datos complejas.
- Alta velocidad de escritura/lectura (latencia < 1 ms).
Limitaciones: sin replicación, sin transacciones, los datos se pierden al reiniciar.
Redis en Go: herramienta potente con amplias capacidades
Redis no es solo un caché, sino un almacenamiento de datos en memoria completo con soporte para cadenas, listas, conjuntos, hashes e incluso colas. Para Go, la mejor