Caching in Go: Redis, Memcached, and Built-in Solutions from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Caching is Critically Important for Go Applications



In modern web development, application response speed directly impacts user experience and conversion rates. The Go language (Golang) is renowned for its performance, but even the most optimized application can encounter bottlenecks when working with databases or external APIs. This is where caching comes to the rescue.



Caching is the temporary storage of frequently requested data in a fast storage medium. In the Go ecosystem, there are three main approaches:



  • Built-in solutions (sync.Map, map + mutex) — for small volumes of data within a single process.
  • Memcached — a distributed in-memory cache, simple and fast.
  • Redis — an advanced storage with support for data structures, persistence, and clustering.


In this article, we will break down each option with practical Go examples, compare their performance, and provide recommendations for choosing the right one.



Built-in Caching in Go: sync.Map and Concurrent Maps



For simple scenarios where the cache does not need to be distributed, Go offers standard tools. The most popular option is sync.Map, introduced in Go 1.9.



Example: sync.Map for Caching API Results



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("Cache contains:", val) }}


Pros: zero dependencies, thread-safety, simplicity.

Cons: no automatic eviction (except TTL via workarounds), no distribution, limited performance under high contention.



For more complex scenarios, use libraries like go-cache or bigcache, which offer TTL, LFU/LRU eviction, and low latency.



Memcached in Go: A Lightweight and Fast Distributed Cache



Memcached is a distributed in-memory caching system. It is ideal for storing simple key-value pairs of small size (up to 1 MB).



Connecting to Memcached from Go



To work with Memcached, use the library github.com/bradfitz/gomemcache.



package main

import ( "fmt" "github.com/bradfitz/gomemcache/memcache")

func main() { mc := memcache.New("localhost:11211")

// Writing to cache err := mc.Set(&memcache.Item{ Key: "user_100", Value: []byte(`{"name":"Bob","age":30}`), Expiration: 300, // 5 minutes }) if err != nil { panic(err) }

// Reading from cache item, err := mc.Get("user_100") if err == nil { fmt.Printf("Data: %s", item.Value) } else { fmt.Println("Cache miss") }}


When to choose Memcached:

  • You need a simple key-value store.
  • Object size does not exceed 1 MB.
  • Persistence or complex data structures are not required.
  • High read/write speed is needed (latency < 1 ms).


Limitations: no replication, no transactions, data is lost on restart.



Redis in Go: A Powerful Tool with Rich Capabilities



Redis is not just a cache, but a full-fledged in-memory data store supporting strings, lists, sets, hashes, and even queues. For Go, the best

Blogs

Book Recommendations