Mastering Go-Redis: High‑Performance Caching, Locks, and Queues
This tutorial walks through why Redis is essential for Go services, how to choose and install the go‑redis client, and provides step‑by‑step code for connections, common commands, cache‑aside, distributed locks, leaderboards, and lightweight queues, followed by performance tuning and best‑practice recommendations.
Why Use Redis with Go?
In high‑concurrency scenarios, databases become bottlenecks; Redis offers in‑memory caching, distributed locks, sorted‑set rankings, and lightweight pub/sub/message queues, dramatically improving response time.
MySQL is a warehouse where access is queued; Redis is a locker where items are retrieved instantly.
Choosing a Go Redis Client
The most popular client is go‑redis , which provides a native Go implementation, built‑in connection pool, and support for clusters, sentinel, pipelines, and transactions.
Installation:
go get github.com/redis/go-redis/v9Quick Start: Basic Operations
1. Connect to Redis
package main
import (
"context"
"fmt"
"github.com/redis/go-redis/v9"
)
var ctx = context.Background()
func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password
DB: 0, // default DB
})
if _, err := rdb.Ping(ctx).Result(); err != nil {
panic(err)
}
fmt.Println("Redis connection successful!")
}2. Common Commands
// Set a key
rdb.Set(ctx, "username", "golang_dev", 0)
// Get a key
val, _ := rdb.Get(ctx, "username").Result()
fmt.Println("username:", val)
// Increment a counter
rdb.Incr(ctx, "counter")
// Set expiration
rdb.Set(ctx, "token:123", "xyz", time.Minute)Typical Business Scenarios
1. Cache‑Aside Pattern
func GetUser(id string) (string, error) {
key := "user:" + id
val, err := rdb.Get(ctx, key).Result()
if err == redis.Nil {
// Cache miss, fetch from DB
user := "db_user_" + id
// Write back to cache
rdb.Set(ctx, key, user, 10*time.Minute)
return user, nil
} else if err != nil {
return "", err
}
return val, nil
}This pattern first checks the cache; on miss it reads the database and writes the result back to Redis.
2. Distributed Lock (Prevent Overselling)
// Simplified distributed lock
func AcquireLock(key, value string, ttl time.Duration) bool {
ok, _ := rdb.SetNX(ctx, key, value, ttl).Result()
return ok
}
func ReleaseLock(key, value string) {
// Ensure the lock is released only by its owner
luaScript := `
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
`
rdb.Eval(ctx, luaScript, []string{key}, value)
}Using SETNX + EXPIRE or the Redlock algorithm avoids concurrent modifications of the same resource.
3. Leaderboard with Sorted Sets
// Add scores
rdb.ZAdd(ctx, "rank", redis.Z{Score: 100, Member: "Alice"})
rdb.ZAdd(ctx, "rank", redis.Z{Score: 200, Member: "Bob"})
// Get top 10
res, _ := rdb.ZRevRangeWithScores(ctx, "rank", 0, 9).Result()
for i, z := range res {
fmt.Printf("Rank %d: %s - %f
", i+1, z.Member, z.Score)
}4. Simple Message Queue
// Producer
rdb.LPush(ctx, "queue", "task1")
// Consumer (blocking)
for {
task, _ := rdb.BRPop(ctx, 0, "queue").Result()
fmt.Println("Consume task:", task[1])
}Performance Optimizations & Best Practices
1. Set Expiration Wisely
Use random expiration times to avoid cache avalanche.
Combine with local in‑process caches.
2. Connection Pool
go‑redis provides a built‑in pool; typical settings:
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
PoolSize: 50, // max connections
MinIdleConns: 10, // minimum idle connections
})3. Batch Operations
Use pipelines or MGet to reduce round‑trip latency.
pipe := rdb.Pipeline()
for i := 0; i < 1000; i++ {
pipe.Set(ctx, fmt.Sprintf("key%d", i), i, 0)
}
_, err := pipe.Exec(ctx)4. Hot Key Mitigation
Add random suffixes to shard hot keys.
Leverage local caches such as freecache or ristretto.
5. Monitoring & Alerting
Key metrics: QPS, latency, memory usage.
Toolchain: Redis Exporter → Prometheus → Grafana.
Conclusion
go‑redis is the preferred client for Go projects.
Typical use cases: caching, distributed locks, leaderboards, lightweight queues.
In high‑concurrency environments, pay attention to connection pooling, batch commands, expiration strategies, and hot‑key handling.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Code Wrench
Focuses on code debugging, performance optimization, and real-world engineering, sharing efficient development tips and pitfall guides. We break down technical challenges in a down-to-earth style, helping you craft handy tools so every line of code becomes a problem‑solving weapon. 🔧💻
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
