go-redis

cache libraryGoGolangRedisclientdistributed cacheNoSQL

GitHub Overview

redis/go-redis

Redis Go client

Stars21,594
Watchers259
Forks2,508
Created:July 25, 2012
Language:Go
License:BSD 2-Clause "Simplified" License

Topics

gogolangredisredis-clientredis-cluster

Star History

redis/go-redis Star History
Data as of: 10/22/2025, 08:07 AM

Cache Library

go-redis

Overview

go-redis (redis/go-redis) is a Redis client library for Go. It provides high performance and rich functionality, enabling connections to Redis servers, data operations, and utilization of advanced Redis features. It supports Redis Cluster, Sentinel, various Redis modules, and offers OpenTelemetry instrumentation capabilities.

Details

go-redis supports all Redis functionality from basic key-value operations to sorted sets, hashes, lists, streams, and Pub/Sub. It supports both RESP2 and RESP3 protocols and includes built-in connection pooling, automatic reconnection, and failover capabilities.

It also provides extended functionality such as OpenTelemetry tracing and metrics, Prometheus metrics, and Redis Search. The library has comprehensive context.Context support, enabling proper timeout and cancellation handling, making it suitable for enterprise-level applications.

Pros and Cons

Pros

  • Complete Redis feature support (Cluster, Sentinel, Modules, etc.)
  • High-performance connection pooling and concurrent processing
  • RESP2/RESP3 protocol support
  • Comprehensive OpenTelemetry instrumentation
  • Full context.Context support
  • Automatic reconnection and failover capabilities
  • Rich Redis extension support (Search, Bloom, etc.)
  • Enterprise-level reliability

Cons

  • Requires Redis server (infrastructure dependency)
  • May be overkill for simple in-memory caching
  • Requires learning Redis-specific concepts (data types, commands, etc.)
  • Slower than pure in-memory cache due to network overhead
  • Requires Redis configuration and tuning knowledge

Reference Links

Code Examples

Basic Setup

package main

import (
    "context"
    "fmt"
    "github.com/redis/go-redis/v9"
)

var ctx = context.Background()

func main() {
    // Create basic Redis client
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password
        DB:       0,  // default DB
    })
    
    // Test connection
    pong, err := rdb.Ping(ctx).Result()
    if err != nil {
        panic(err)
    }
    fmt.Println("Connected to Redis:", pong)
}

Basic Set/Get Operations

// Store string
err := rdb.Set(ctx, "user:name", "John Doe", 0).Err()
if err != nil {
    panic(err)
}

// Get value
val, err := rdb.Get(ctx, "user:name").Result()
if err == redis.Nil {
    fmt.Println("key does not exist")
} else if err != nil {
    panic(err)
} else {
    fmt.Println("user:name", val)
}

// Store with expiration
err = rdb.Set(ctx, "session:123", "active", 30*time.Minute).Err()
if err != nil {
    panic(err)
}

URL Connection and Configuration Options

// Connect using URL
url := "redis://user:password@localhost:6379/0?protocol=3"
opts, err := redis.ParseURL(url)
if err != nil {
    panic(err)
}
rdb := redis.NewClient(opts)

// Advanced configuration options
rdb := redis.NewClient(&redis.Options{
    Addr:         "localhost:6379",
    Password:     "mypassword",
    DB:           0,
    PoolSize:     10,               // Connection pool size
    MinIdleConns: 5,                // Minimum idle connections
    MaxIdleTime:  5 * time.Minute,  // Idle timeout
    DialTimeout:  5 * time.Second,  // Connection timeout
    ReadTimeout:  3 * time.Second,  // Read timeout
    WriteTimeout: 3 * time.Second,  // Write timeout
    Protocol:     3,                // Use RESP3 protocol
})

Advanced Redis Operations

// Hash operations
err := rdb.HSet(ctx, "user:123", map[string]interface{}{
    "name":  "John Doe",
    "email": "[email protected]",
    "age":   30,
}).Err()

userInfo := rdb.HGetAll(ctx, "user:123").Val()
fmt.Printf("User info: %v\n", userInfo)

// List operations
rdb.LPush(ctx, "tasks", "task1", "task2", "task3")
tasks := rdb.LRange(ctx, "tasks", 0, -1).Val()
fmt.Printf("Tasks: %v\n", tasks)

// Sorted set operations
rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 100, Member: "player1"})
rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 85, Member: "player2"})

// Get top 10
topPlayers := rdb.ZRevRangeWithScores(ctx, "leaderboard", 0, 9).Val()
for _, player := range topPlayers {
    fmt.Printf("Player: %s, Score: %.0f\n", player.Member, player.Score)
}

Pipeline Processing

// Batch processing using pipeline
pipe := rdb.Pipeline()

incr := pipe.Incr(ctx, "counter")
pipe.Expire(ctx, "counter", time.Hour)

// Execute pipeline
_, err := pipe.Exec(ctx)
if err != nil {
    panic(err)
}

// Get results
fmt.Println("Counter value:", incr.Val())

Transactions (MULTI/EXEC)

// Execute transaction
err := rdb.Watch(ctx, func(tx *redis.Tx) error {
    // Get current value
    currentVal := tx.Get(ctx, "balance").Val()
    balance, _ := strconv.Atoi(currentVal)
    
    if balance < 100 {
        return fmt.Errorf("insufficient balance")
    }
    
    // Start transaction
    _, err := tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
        pipe.Decr(ctx, "balance")
        pipe.Incr(ctx, "spent")
        return nil
    })
    
    return err
}, "balance")

if err != nil {
    fmt.Printf("Transaction failed: %v\n", err)
}

Pub/Sub Functionality

// Publisher
func publisher(rdb *redis.Client) {
    for i := 0; i < 10; i++ {
        message := fmt.Sprintf("Message %d", i)
        err := rdb.Publish(ctx, "notifications", message).Err()
        if err != nil {
            panic(err)
        }
        time.Sleep(1 * time.Second)
    }
}

// Subscriber
func subscriber(rdb *redis.Client) {
    pubsub := rdb.Subscribe(ctx, "notifications")
    defer pubsub.Close()
    
    ch := pubsub.Channel()
    
    for msg := range ch {
        fmt.Printf("Received: %s\n", msg.Payload)
    }
}

Redis Cluster Connection

// Cluster client
rdb := redis.NewClusterClient(&redis.ClusterOptions{
    Addrs: []string{
        "localhost:7000",
        "localhost:7001", 
        "localhost:7002",
    },
    Password: "cluster-password",
})

// Use same API as regular operations
err := rdb.Set(ctx, "cluster-key", "cluster-value", 0).Err()
if err != nil {
    panic(err)
}

OpenTelemetry Integration

import (
    "github.com/redis/go-redis/v9"
    "github.com/redis/go-redis/extra/redisotel/v9"
)

// OpenTelemetry instrumentation
rdb := redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
})

// Enable tracing and metrics
err := redisotel.InstrumentTracing(rdb)
if err != nil {
    panic(err)
}

err = redisotel.InstrumentMetrics(rdb)
if err != nil {
    panic(err)
}

Error Handling and Retry

// Custom retry configuration
rdb := redis.NewClient(&redis.Options{
    Addr:         "localhost:6379",
    MaxRetries:   3,
    MinRetryBackoff: 8 * time.Millisecond,
    MaxRetryBackoff: 512 * time.Millisecond,
})

// Error handling
val, err := rdb.Get(ctx, "nonexistent").Result()
switch {
case err == redis.Nil:
    fmt.Println("Key does not exist")
case err != nil:
    fmt.Printf("Error occurred: %v\n", err)
default:
    fmt.Printf("Value: %s\n", val)
}