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.