Caching in Go (Golang): Redis and Other Solutions
Caching is one of the key tools for improving the performance of Go applications. It helps reduce response time, lower the load on databases and external APIs. In this article, we will cover the main approaches to caching in Go: using Redis as an external storage, built-in in-memory caching, and group caching using the groupcache library.
1. Why is caching needed in Go?
Go is a language focused on high performance, but even the fastest queries to a database or external services can become a bottleneck. Caching helps:
- Reduce latency for repeated requests.
- Lower the load on databases and third-party APIs.
- Increase server throughput.
- Smooth out peak loads.
2. Redis — Distributed Caching
Redis is the most popular solution for external caching in Go. It works as an in-memory store with support for TTL, persistence, and complex data structures.
Connecting Redis in Go
To work with Redis in Go, the go-redis library is most commonly used. Installation:
go get github.com/redis/go-redis/v9Example: Simple Caching with 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", })
// Set a value with a TTL of 10 seconds err := rdb.Set(ctx, "user:42", `{"name":"Alice"}`, 10*time.Second).Err() if err != nil { panic(err) }
// Get the value val, err := rdb.Get(ctx, "user:42").Result() if err != nil { fmt.Println("Cache miss") } else { fmt.Println("Cache hit:", val) }}Cache Invalidation Strategies in Redis
- TTL (Time To Live) — automatic deletion after expiration.
- Lazy invalidation — clearing the cache when data is updated.
- Deletion by key — calling
DELfor a specific key. - Cache-Aside pattern — the application manages the cache itself: first checks Redis, on a miss loads from the database and saves to the cache.
3. In-memory Caching in Go
For local caching without external dependencies, you can use built-in Go structures or specialized libraries.
Simple In-memory Cache with 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("Found:", val) }}Freecache Library
freecache is a high-performance in-memory library with TTL support and low memory consumption. Installation:
go get github.com/coocood/freecachecache := freecache.NewCache(100 * 1024 * 1024) // 100 MBcache.Set([]by Also in library
tRPC for TypeScript: Complete Guide with Examples
HTTP Client for Java: Top Libraries for Working with HTTP
Working with Excel in TypeScript: Libraries, Tools, and Code Examples
Clikt: Powerful CLI Framework for Kotlin with Declarative Syntax