Redis Client Libraries for Go and Python

Go Redis Client Implementation

Installation

The go-redis/redis library provides a rich set of functions for executing Redis commands, unlike older libraries that rely solely on a single execution method. This library supports both sentinel and cluster configurations.

Insatllation command:

go get github.com/go-redis/redis/v8

Connection Methods

Standalone Connection:

client := redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
})

TLS Configuration:

client := redis.NewClient(&redis.Options{
    TLSConfig: &tls.Config{
        MinVersion: tls.VersionTLS12,
    },
})

Cluster Connection:

clusterClient := redis.NewClusterClient(&redis.ClusterOptions{
    Addrs: []string{":7000", ":7001", ":7002"},
})

Sentinel Connection:

failoverClient := redis.NewFailoverClient(&redis.FailoverOptions{
    MasterName:    "master-name",
    SentinelAddrs: []string{":9126", ":9127"},
})

Basic Operations

func executeCommands() {
    ctx := context.Background()
    
    // Get operation
    val, err := client.Get(ctx, "sample_key").Result()
    if err != nil {
        log.Printf("Error: %v", err)
    }
    
    // Set operation
    err = client.Set(ctx, "sample_key", "value", time.Hour).Err()
    if err != nil {
        log.Printf("Set error: %v", err)
    }
}

Custom Command Execution

For unsupported operations, the Do method allows arbitrary command execution:

func customCommand() {
    ctx := context.Background()
    
    err := client.Do(ctx, "set", "custom_key", 42, "EX", 3600).Err()
    if err != nil {
        log.Printf("Command failed: %v", err)
    }
    
    result, err := client.Do(ctx, "get", "custom_key").Result()
    if err != nil {
        log.Printf("Get failed: %v", err)
    }
    fmt.Println(result)
}

Handling Missing Keys

func fetchValue(key, fallback string) (string, error) {
    ctx := context.Background()
    
    val, err := client.Get(ctx, key).Result()
    if err != nil {
        if errors.Is(err, redis.Nil) {
            return fallback, nil
        }
        return "", err
    }
    return val, nil
}

Sorted Set Operations

type ScoredMember struct {
    Score  float64
    Member string
}

func sortedSetOperations() {
    ctx := context.Background()
    key := "programming_scores"
    
    members := []redis.Z{
        {Score: 95.0, Member: "Go"},
        {Score: 87.5, Member: "Python"},
        {Score: 92.3, Member: "Java"},
    }
    
    err := client.ZAdd(ctx, key, members...).Err()
    if err != nil {
        log.Printf("ZAdd error: %v", err)
        return
    }
    
    // Increment score
    newScore, err := client.ZIncrBy(ctx, key, 5.0, "Go").Result()
    if err != nil {
        log.Printf("Increment error: %v", err)
        return
    }
    fmt.Printf("Updated score: %.2f\n", newScore)
    
    // Top 3 scores
    topResults := client.ZRevRangeWithScores(ctx, key, 0, 2).Val()
    for _, item := range topResults {
        fmt.Printf("%s: %.1f\n", item.Member, item.Score)
    }
}

Key Scanning

func scanMatchingKeys(pattern string) {
    ctx := context.Background()
    
    iter := client.Scan(ctx, 0, pattern, 0).Iterator()
    for iter.Next(ctx) {
        fmt.Printf("Found key: %s\n", iter.Val())
    }
    
    if err := iter.Err(); err != nil {
        log.Printf("Scan error: %v", err)
    }
}

func deleteMatchingKeys(pattern string) {
    ctx := context.Background()
    
    iter := client.Scan(ctx, 0, pattern, 0).Iterator()
    for iter.Next(ctx) {
        client.Del(ctx, iter.Val())
    }
}

Pipeline Operations

func batchOperations() {
    pipe := client.Pipeline()
    
    counter := pipe.Incr(context.Background(), "batch_counter")
    pipe.Expire(context.Background(), "batch_counter", time.Hour)
    
    _, err := pipe.Exec(context.Background())
    if err != nil {
        log.Printf("Pipeline error: %v", err)
    }
    
    fmt.Printf("Counter value: %d\n", counter.Val())
}

func pipelinedBatch() {
    ctx := context.Background()
    var counterCmd *redis.IntCmd
    
    cmds, err := client.Pipelined(ctx, func(p redis.Pipeliner) error {
        counterCmd = p.Incr(ctx, "pipelined_counter")
        p.Expire(ctx, "pipelined_counter", time.Hour)
        return nil
    })
    
    if err != nil {
        log.Printf("Pipelined error: %v", err)
    }
    
    fmt.Printf("Final count: %d\n", counterCmd.Val())
}

Transaction Support

func transactionExample() {
    ctx := context.Background()
    
    pipe := client.TxPipeline()
    incr := pipe.Incr(ctx, "transaction_counter")
    pipe.Expire(ctx, "transaction_counter", time.Hour)
    
    _, err := pipe.Exec(ctx)
    if err != nil {
        log.Printf("Transaction error: %v", err)
    }
    
    fmt.Printf("Transaction result: %d\n", incr.Val())
}

Distributed Locking

import (
    "github.com/go-redsync/redsync/v4"
    "github.com/go-redsync/redsync/v4/redis/goredis/v8"
)

func distributedLock() {
    client := redis.NewClient(&redis.Options{
        Addr: "localhost:6379",
    })
    
    pool := goredis.NewPool(client)
    rs := redsync.New(pool)
    
    mutex := rs.NewMutex("resource_lock")
    
    if err := mutex.Lock(); err != nil {
        log.Fatalf("Lock acquisition failed: %v", err)
    }
    
    // Critical section
    fmt.Println("Resource locked")
    
    if _, err := mutex.Unlock(); err != nil {
        log.Printf("Unlock error: %v", err)
    }
}

Python Redis Integration

Connection Setup

Standard Connection:

import redis

# Direct connection
connection = redis.Redis(host='localhost', port=6379, db=0)

# Connection pooling
pool = redis.ConnectionPool(host='localhost', port=6379, db=0)
connection = redis.Redis(connection_pool=pool)

Sentinel Configuration:

from redis.sentinel import Sentinel

sentinels = [
    ("192.168.1.10", 26379),
    ("192.168.1.11", 26379),
]

sentinel_client = Sentinel(sentinels)
master_db = sentinel_client.master_for('mymaster', db=0)
slave_db = sentinel_client.slave_for('mymaster', db=0)

Cluster Connection:

import redis

startup_nodes = [
    {"host": "127.0.0.1", "port": "7000"},
    {"host": "127.0.0.1", "port": "7001"},
]

cluster_client = redis.RedisCluster(
    startup_nodes=startup_nodes, 
    decode_responses=True
)

Django Integration

Direct Redis Usage:

import redis

REDIS_POOL = redis.ConnectionPool(
    host='localhost', 
    port=6379, 
    max_connections=1000
)

def view_handler(request):
    conn = redis.Redis(connection_pool=REDIS_POOL)
    conn.hset('user_data', 'status', 'active')
    return HttpResponse('Data stored')

Django Cache Backend:

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/5",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
        }
    }
}

# Usage
from django_redis import get_redis_connection
conn = get_redis_connection('default')

from django.core.cache import cache
cache.set("key", "value")

Key Differences: Pipeline vs Transactions

Pipelines optimiez network roundtrips by batching multiple commands, while transactions ensure atomicity through server-side MULTI/EXEC blocks. Pipelines improve throughput but don't guarantee ACID properties across commands.

Tags: Redis Go python database distributed-systems

Posted on Thu, 11 Jun 2026 18:25:21 +0000 by kessels1234