### Install go-redis/cache Source: https://redis.uptrace.dev/guide/go-redis-cache.html Install the go-redis/cache library using the go get command. ```bash go get github.com/go-redis/cache/v8 ``` -------------------------------- ### Install redis_rate with go get Source: https://redis.uptrace.dev/guide/go-redis-rate-limiting.html Install the redis_rate library version v10 using the go get command. ```bash go get github.com/go-redis/redis_rate/v10 ``` -------------------------------- ### Connect to Redis and Set/Get Keys with go-redis Source: https://redis.uptrace.dev/ Basic example of connecting to a local Redis server, setting a key, getting it, and handling a missing key with redis.Nil. The output shows the expected results. ```go package main import ( "context" "github.com/redis/go-redis/v9" ) func main() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB }) err := rdb.Set(ctx, "key", "value", 0).Err() if err != nil { panic(err) } val, err := rdb.Get(ctx, "key").Result() if err != nil { panic(err) } fmt.Println("key", val) val2, err := rdb.Get(ctx, "key2").Result() if err == redis.Nil { fmt.Println("key2 does not exist") } else if err != nil { panic(err) } else { fmt.Println("key2", val2) } // Output: key value // key2 does not exist } ``` -------------------------------- ### Install go-redis v9 Source: https://redis.uptrace.dev/guide/go-redis.html Installs the go-redis v9 package using go get. ```bash go get github.com/redis/go-redis/v9 ``` -------------------------------- ### Initialize a Go module Source: https://redis.uptrace.dev/guide/go-redis.html Run this command to initialize a Go module before installing go-redis, which requires Go modules. ```bash go mod init github.com/my/repo ``` -------------------------------- ### Install redisotel module Source: https://redis.uptrace.dev/guide/go-redis-monitoring.html Install the redisotel OpenTelemetry instrumentation module for go-redis using go get. ```bash go get github.com/redis/go-redis/extra/redisotel/v9 ``` -------------------------------- ### Use the Ring client to set a key Source: https://redis.uptrace.dev/guide/ring.html Shows how to use the Ring client as usual, with a Set command. The example panics if the command fails. ```go if err := rdb.Set(ctx, "foo", "bar", 0).Err(); err != nil { panic(err) } ``` -------------------------------- ### Populate Redis hash fields using a pipeline Source: https://redis.uptrace.dev/guide/scanning-hash-fields.html Creates a Redis client and uses a pipeline to set hash fields for the example. This is required before scanning. ```go rdb := redis.NewClient(&redis.Options{ Addr: ":6379", }) if _, err := rdb.Pipelined(ctx, func(rdb redis.Pipeliner) error { rdb.HSet(ctx, "key", "str1", "hello") rdb.HSet(ctx, "key", "str2", "world") rdb.HSet(ctx, "key", "int", 123) rdb.HSet(ctx, "key", "bool", 1) return nil }); err != nil { panic(err) } ``` -------------------------------- ### Create UniversalClient with MasterName Source: https://redis.uptrace.dev/guide/universal.html When MasterName is specified, NewUniversalClient returns a *redis.FailoverClient (sentinel-backed). The example shows the Addrs and MasterName options. ```go // rdb is *redis.FailoverClient. rdb := NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{":6379"}, MasterName: "mymaster", }) ``` -------------------------------- ### Iterate over pipeline commands to retrieve results Source: https://redis.uptrace.dev/guide/go-redis-pipelines.html Queues 100 Get commands in a pipeline and iterates over the returned commands to retrieve each result. Demonstrates that pipelines return the executed commands. ```go cmds, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { for i := 0; i < 100; i++ { pipe.Get(ctx, fmt.Sprintf("key%d", i)) } return nil }) if err != nil { panic(err) } for _, cmd := range cmds { fmt.Println(cmd.(*redis.StringCmd).Val()) } ``` -------------------------------- ### Use Text helper on Cmd Source: https://redis.uptrace.dev/guide/go-redis.html Uses the Text() helper on the Cmd returned by rdb.Do to get the string value with proper error handling. ```go // Text is a shortcut for get.Val().(string) with proper error handling. val, err := rdb.Do(ctx, "get", "key").Text() fmt.Println(val, err) ``` -------------------------------- ### Create UniversalClient with multiple addresses Source: https://redis.uptrace.dev/guide/universal.html When two or more addresses are provided, NewUniversalClient returns a *redis.ClusterClient. The example shows the Addrs option with two addresses. ```go // rdb is *redis.ClusterClient. rdb := NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{":6379", ":6380"}, }) ``` -------------------------------- ### Handle redis.Nil error Source: https://redis.uptrace.dev/guide/go-redis.html Uses redis.Nil to distinguish between an empty string reply and a nil reply (key does not exist) when getting a key. ```go val, err := rdb.Get(ctx, "key").Result() switch { case err == redis.Nil: fmt.Println("key does not exist") case err != nil: fmt.Println("Get failed", err) case val == "": fmt.Println("value is empty") } ``` -------------------------------- ### Publish a message with rdb.Publish Source: https://redis.uptrace.dev/guide/go-redis-pubsub.html Publishes a message to a channel. The Err() method returns an error if the publish fails, and the example panics on error. ```go err := rdb.Publish(ctx, "mychannel1", "payload").Err() if err != nil { panic(err) } ``` -------------------------------- ### Execute a Redis command and get result Source: https://redis.uptrace.dev/guide/go-redis.html Executes a Redis command and retrieves the result and error using the Result() method. ```go val, err := rdb.Get(ctx, "key").Result() fmt.Println(val) ``` -------------------------------- ### Count distinct elements with PFADD and PFCOUNT in go-redis Source: https://redis.uptrace.dev/guide/go-redis-hll.html This example creates a Redis client, flushes the database, adds 10 elements to a HyperLogLog set named 'myset' using PFAdd, and then retrieves the approximate cardinality with PFCount. The output prints 'set cardinality 10'. ```go package main import ( "context" "fmt" "github.com/redis/go-redis/v9" ) func main() { ctx := context.Background() rdb := redis.NewClient(&redis.Options{ Addr: ":6379", }) _ = rdb.FlushDB(ctx).Err() for i := 0; i < 10; i++ { if err := rdb.PFAdd(ctx, "myset", fmt.Sprint(i)).Err(); err != nil { panic(err) } } card, err := rdb.PFCount(ctx, "myset").Result() if err != nil { panic(err) } fmt.Println("set cardinality", card) } ``` -------------------------------- ### Create UniversalClient with single address Source: https://redis.uptrace.dev/guide/universal.html When only one address is provided and no MasterName, NewUniversalClient returns a *redis.Client (single-node). The example shows the Addrs option with a single address. ```go // rdb is *redis.Client. rdb := NewUniversalClient(&redis.UniversalOptions{ Addrs: []string{":6379"}, }) ``` -------------------------------- ### Redis WATCH and MULTI/EXEC transaction example Source: https://redis.uptrace.dev/guide/go-redis-pipelines.html Shows the Redis command sequence for optimistic locking: WATCH a key, read its value, then use MULTI/EXEC to set the new value only if the key hasn't changed. ```redis WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC ``` -------------------------------- ### Using Conn to set and get client name Source: https://redis.uptrace.dev/guide/go-redis.html Creates a single Redis connection with rdb.Conn, defers its close, sets a client name with ClientSetName, and retrieves it with ClientGetName. Panics on errors and prints the client name. ```go cn := rdb.Conn(ctx) defer cn.Close() if err := cn.ClientSetName(ctx, "myclient").Err(); err != nil { panic(err) } name, err := cn.ClientGetName(ctx).Result() if err != nil { panic(err) } fmt.Println("client name", name) ``` -------------------------------- ### Change consistent hash implementation with NewConsistentHash Source: https://redis.uptrace.dev/guide/ring.html Shows how to replace the default Rendezvous hash with a custom consistent hash implementation using the NewConsistentHash option. The example uses the groupcache consistenthash package. ```go import "github.com/golang/groupcache/consistenthash" ring := redis.NewRing(&redis.RingOptions{ NewConsistentHash: func() { return consistenthash.New(100, crc32.ChecksumIEEE) }, }) ``` -------------------------------- ### Implement transactional INCR with WATCH and TxPipelined Source: https://redis.uptrace.dev/guide/go-redis-pipelines.html Implements a transactional INCR using GET, SET, and WATCH with optimistic locking. Uses redis.TxFailedErr to detect lost locks and retries up to maxRetries (1000). ```go // Redis transactions use optimistic locking. const maxRetries = 1000 // Increment transactionally increments the key using GET and SET commands. func increment(key string) error { // Transactional function. txf := func(tx *redis.Tx) error { // Get the current value or zero. n, err := tx.Get(ctx, key).Int() if err != nil && err != redis.Nil { return err } // Actual operation (local in optimistic lock). n++ // Operation is commited only if the watched keys remain unchanged. _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error { pipe.Set(ctx, key, n, 0) return nil }) return err } // Retry if the key has been changed. for i := 0; i < maxRetries; i++ { err := rdb.Watch(ctx, txf, key) if err == nil { // Success. return nil } if err == redis.TxFailedErr { // Optimistic lock lost. Retry. continue } // Return any other error. return err } return errors.New("increment reached maximum number of retries") } ``` -------------------------------- ### Compare go-redis and redigo command APIs Source: https://redis.uptrace.dev/guide/go-redis-vs-redigo.html Demonstrates the difference between the type-safe API of go-redis and the print-like API of redigo. ```go // go-redis timeout := time.Second _, err := rdb.Set(ctx, "key", "value", timeout).Result() // redigo _, err := conn.Do("SET", "key", "value", "EX", 1) ``` -------------------------------- ### Compile and load RedisBloom module Source: https://redis.uptrace.dev/guide/bloom-cuckoo-count-min-top-k.html Clone and build the RedisBloom module, then load it into a Redis server. The module must be compiled before loading. ```bash git clone --recursive https://github.com/RedisBloom/RedisBloom.git cd redisbloom make ``` ```bash /path/to/redis-server --loadmodule ./redisbloom.so ``` -------------------------------- ### Count-Min sketch with CMS.INITBYPROB, CMS.INCRBY, and CMS.QUERY Source: https://redis.uptrace.dev/guide/bloom-cuckoo-count-min-top-k.html Initialize a count-min sketch with CMS.INITBYPROB, increment counts with CMS.INCRBY, and query approximate counts with CMS.QUERY. The function simulates 10,000 random increments and prints the approximate vs actual counts. ```go func countMinSketch(ctx context.Context, rdb *redis.Client) { if err := rdb.Do(ctx, "CMS.INITBYPROB", "count_min", 0.001, 0.01).Err(); err != nil { panic(err) } items := []string{"item1", "item2", "item3", "item4", "item5"} counts := make(map[string]int, len(items)) for i := 0; i < 10000; i++ { n := rand.Intn(len(items)) item := items[n] if err := rdb.Do(ctx, "CMS.INCRBY", "count_min", item, 1).Err(); err != nil { panic(err) } counts[item]++ } for item, count := range counts { ns, err := rdb.Do(ctx, "CMS.QUERY", "count_min", item).Int64Slice() if err != nil { panic(err) } fmt.Printf("%s: count-min=%d actual=%d\n", item, ns[0], count) } } ``` -------------------------------- ### Connect to Redis Server with redis.NewClient Source: https://redis.uptrace.dev/guide/go-redis.html Creates a Redis client with default options: address localhost:6379, no password, and default DB 0. ```go import "github.com/redis/go-redis/v9" rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", Password: "", // no password set DB: 0, // use default DB }) ``` -------------------------------- ### Execute multiple commands with rdb.Pipeline() and Exec Source: https://redis.uptrace.dev/guide/go-redis-pipelines.html Creates a pipeline with rdb.Pipeline(), queues Incr and Expire commands, then executes them with Exec. The command results are only available after Exec is called. ```go pipe := rdb.Pipeline() incr := pipe.Incr(ctx, "pipeline_counter") pipe.Expire(ctx, "pipeline_counter", time.Hour) cmds, err := pipe.Exec(ctx) if err != nil { panic(err) } // The value is available only after Exec is called. fmt.Println(incr.Val()) ``` -------------------------------- ### Enable TLS with tls.Config Source: https://redis.uptrace.dev/guide/go-redis.html Enables TLS by providing an empty tls.Config. For private certs, specify them in the Certificates field. ```go rdb := redis.NewClient(&redis.Options{ TLSConfig: &tls.Config{ MinVersion: tls.VersionTLS12, //Certificates: []tls.Certificate{cert} }, }) ``` -------------------------------- ### Create a Redis Ring cluster with 3 shards Source: https://redis.uptrace.dev/guide/ring.html Initializes a Ring client with three shards using the redis.NewRing function. The Addrs map maps shard names to host:port addresses. ```go import "github.com/redis/go-redis/v9" rdb := redis.NewRing(&redis.RingOptions{ Addrs: map[string]string{ // shardName => host:port "shard1": "localhost:7000", "shard2": "localhost:7001", "shard3": "localhost:7002", }, }) ``` -------------------------------- ### Using go-redis/cache with Redis Source: https://redis.uptrace.dev/guide/go-redis-cache.html Creates a Redis client and a go-redis/cache instance, then uses the Once method to cache an object under the key 'mykey'. The Do function provides the value to cache if not present. ```go rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) mycache := cache.New(&cache.Options{ Redis: rdb, }) obj := new(Object) err := mycache.Once(&cache.Item{ Key: "mykey", Value: obj, // destination Do: func(*cache.Item) (interface{}, error) { return &Object{ Str: "mystring", Num: 42, }, nil }, }) if err != nil { panic(err) } ``` -------------------------------- ### Execute unsupported command with rdb.Do Source: https://redis.uptrace.dev/guide/go-redis.html Executes an arbitrary or custom command using rdb.Do and handles the redis.Nil error for missing keys. ```go val, err := rdb.Do(ctx, "get", "key").Result() if err != nil { if err == redis.Nil { fmt.Println("key does not exists") return } panic(err) } fmt.Println(val.(string)) ``` -------------------------------- ### Use rdb.TxPipelined to wrap pipeline in MULTI/EXEC Source: https://redis.uptrace.dev/guide/go-redis-pipelines.html Wraps a pipeline with MULTI and EXEC using TxPipelined. The comment shows the resulting Redis commands. This is not very useful on its own. ```go cmds, err := rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error { for i := 0; i < 100; i++ { pipe.Get(ctx, fmt.Sprintf("key%d", i)) } return nil }) if err != nil { panic(err) } // MULTI // GET key0 // GET key1 // ... // GET key99 // EXEC ``` -------------------------------- ### List of Cmd helper methods Source: https://redis.uptrace.dev/guide/go-redis.html Lists the helper methods available on the Cmd type to convert the interface{} value to various types. ```go s, err := cmd.Text() flag, err := cmd.Bool() num, err := cmd.Int() num, err := cmd.Int64() num, err := cmd.Uint64() num, err := cmd.Float32() num, err := cmd.Float64() ss, err := cmd.StringSlice() ns, err := cmd.Int64Slice() ns, err := cmd.Uint64Slice() fs, err := cmd.Float32Slice() fs, err := cmd.Float64Slice() bs, err := cmd.BoolSlice() ``` -------------------------------- ### Perform manual connection management in go-redis Source: https://redis.uptrace.dev/guide/go-redis-vs-redigo.html Shows how to manually manage connections in go-redis when necessary. ```go // go-redis manual connection management conn := rdb.Conn(ctx) _, err := conn.Set(...).Result() conn.Close() ``` -------------------------------- ### Use go-redis print-like API Source: https://redis.uptrace.dev/guide/go-redis-vs-redigo.html Shows that go-redis also supports a print-like API similar to redigo. ```go // go-redis print-like API ok, err := rdb.Do(ctx, "SET" "key", "value", "EX", 1).Bool() ``` -------------------------------- ### Bloom filter with BF.ADD and BF.EXISTS Source: https://redis.uptrace.dev/guide/bloom-cuckoo-count-min-top-k.html Use the general Do function to execute BF.ADD and BF.EXISTS commands, then retrieve results with Cmd helpers. The function adds an item and checks for existence, printing whether each item exists. ```go func bloomFilter(ctx context.Context, rdb *redis.Client) { inserted, err := rdb.Do(ctx, "BF.ADD", "bf_key", "item0").Bool() if err != nil { panic(err) } if inserted { fmt.Println("item0 was inserted") } for _, item := range []string{"item0", "item1"} { exists, err := rdb.Do(ctx, "BF.EXISTS", "bf_key", item).Bool() if err != nil { panic(err) } if exists { fmt.Printf("%s does exist\n", item) } else { fmt.Printf("%s does not exist\n", item) } } } ``` -------------------------------- ### Connect to Redis Server via Sentinel with NewFailoverClient Source: https://redis.uptrace.dev/guide/go-redis-sentinel.html Creates a failover client that connects to a Redis Server managed by Redis Sentinel. Requires the master name and Sentinel addresses. Use this for standard read/write operations. ```go import "github.com/redis/go-redis/v9" rdb := redis.NewFailoverClient(&redis.FailoverOptions{ MasterName: "master-name", SentinelAddrs: []string{":9126", ":9127", ":9128"}, }) ``` -------------------------------- ### Create limiter and allow request Source: https://redis.uptrace.dev/guide/go-redis-rate-limiting.html Create a Redis client and a redis_rate limiter, then call Allow to check if a request is allowed. The result includes the allowed flag and remaining count. ```go rdb := redis.NewClient(&redis.Options{ Addr: "localhost:6379", }) limiter := redis_rate.NewLimiter(rdb) res, err := limiter.Allow(ctx, "project:123", redis_rate.PerSecond(10)) if err != nil { panic(err) } fmt.Println("allowed", res.Allowed, "remaining", res.Remaining) ``` -------------------------------- ### Top-K with TOPK.RESERVE, TOPK.INCRBY, TOPK.LIST, and TOPK.COUNT Source: https://redis.uptrace.dev/guide/bloom-cuckoo-count-min-top-k.html Reserve a top-k structure with TOPK.RESERVE, increment counts with TOPK.INCRBY, list the top items with TOPK.LIST, and query counts with TOPK.COUNT. The function demonstrates maintaining a list of the k most frequent items. ```go func topK(ctx context.Context, rdb *redis.Client) { if err := rdb.Do(ctx, "TOPK.RESERVE", "top_items", 3).Err(); err != nil { panic(err) } counts := map[string]int{ "item1": 1000, "item2": 2000, "item3": 3000, "item4": 4000, "item5": 5000, "item6": 6000, } for item, count := range counts { for i := 0; i < count; i++ { if err := rdb.Do(ctx, "TOPK.INCRBY", "top_items", item, 1).Err(); err != nil { panic(err) } } } items, err := rdb.Do(ctx, "TOPK.LIST", "top_items").StringSlice() if err != nil { panic(err) } for _, item := range items { ns, err := rdb.Do(ctx, "TOPK.COUNT", "top_items", item).Int64Slice() if err != nil { panic(err) } fmt.Printf("%s: top-k=%d actual=%d\n", item, ns[0], counts[item]) } } ``` -------------------------------- ### Connect using a connection string with redis.ParseURL Source: https://redis.uptrace.dev/guide/go-redis.html Parses a Redis connection string and creates a client. Panics if the URL is invalid. ```go opt, err := redis.ParseURL("redis://:@localhost:6379/") if err != nil { panic(err) } rdb := redis.NewClient(opt) ``` -------------------------------- ### Create a context for Redis commands Source: https://redis.uptrace.dev/guide/go-redis.html Creates a background context to pass to Redis commands for setting timeouts or propagating information like tracing context. ```go ctx := context.Background() ``` -------------------------------- ### Customize per-shard connection options with NewClient Source: https://redis.uptrace.dev/guide/ring.html Shows how to change shard connection options by providing a NewClient function in RingOptions. The function receives the shard's options and can modify username and password before creating the client. ```go rdb := redis.NewRing(&redis.RingOptions{ NewClient: func(opt *redis.Options) *redis.NewClient { user, pass := userPassForAddr(opt.Addr) opt.Username = user opt.Password = pass return redis.NewClient(opt) }, }) ``` -------------------------------- ### Connect to Redis Cluster with redis.NewClusterClient Source: https://redis.uptrace.dev/guide/go-redis-cluster.html Creates a Redis Cluster client using the go-redis library. Specify the cluster node addresses in the Addrs field. Optionally enable RouteByLatency or RouteRandomly to change command routing behavior. ```go import "github.com/redis/go-redis/v9" rdb := redis.NewClusterClient(&redis.ClusterOptions{ Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"}, // To route commands by latency or randomly, enable one of the following. //RouteByLatency: true, //RouteRandomly: true, }) ``` -------------------------------- ### Iterate over shards with ForEachShard Source: https://redis.uptrace.dev/guide/go-redis-cluster.html Iterates over each shard in the cluster and performs a Ping command. The callback receives the shard's client and context. If any shard returns an error, the iteration stops and the error is returned. ```go err := rdb.ForEachShard(ctx, func(ctx context.Context, shard *redis.Client) error { return shard.Ping(ctx).Err() }) if err != nil { panic(err) } ``` -------------------------------- ### Customize options per shard with NewClient Source: https://redis.uptrace.dev/guide/go-redis-cluster.html Configures a cluster client to use a custom NewClient function that sets username and password for each shard based on its address. The function receives the default options and returns a new client with modified credentials. ```go rdb := redis.NewClusterClient(&redis.ClusterOptions{ NewClient: func(opt *redis.Options) *redis.NewClient { user, pass := userPassForAddr(opt.Addr) opt.Username = user opt.Password = pass return redis.NewClient(opt) }, }) ``` -------------------------------- ### Connect to Redis Sentinel with NewSentinelClient Source: https://redis.uptrace.dev/guide/go-redis-sentinel.html Connects directly to a Redis Sentinel instance. Use GetMasterAddrByName to retrieve the master address. Requires the Sentinel address. ```go import "github.com/redis/go-redis/v9" sentinel := redis.NewSentinelClient(&redis.Options{ Addr: ":9126", }) addr, err := sentinel.GetMasterAddrByName(ctx, "master-name").Result() ``` -------------------------------- ### Receive messages using pubsub.Channel Source: https://redis.uptrace.dev/guide/go-redis-pubsub.html Simplest way to receive messages: uses a Go channel that is closed together with the subscription. Iterates over the channel and prints each message's channel and payload. ```go ch := pubsub.Channel() for msg := range ch { fmt.Println(msg.Channel, msg.Payload) } ``` -------------------------------- ### Iterate over Redis keys using SCAN Source: https://redis.uptrace.dev/guide/get-all-keys.html Basic go-redis loop using rdb.Scan with a cursor to iterate over keys matching 'prefix:*'. It prints each key and stops when the cursor is zero. ```Go var cursor uint64 for { var keys []string var err error keys, cursor, err = rdb.Scan(ctx, cursor, "prefix:*", 0).Result() if err != nil { panic(err) } for _, key := range keys { fmt.Println("key", key) } if cursor == 0 { // no more keys break } } ``` -------------------------------- ### Scan all hash fields with HGetAll Source: https://redis.uptrace.dev/guide/scanning-hash-fields.html Uses HGetAll to scan all fields into a Model struct. ```go var model1 Model // Scan all fields into the model. if err := rdb.HGetAll(ctx, "key").Scan(&model1); err != nil { panic(err) } ``` -------------------------------- ### Add local TinyLFU cache to go-redis/cache Source: https://redis.uptrace.dev/guide/go-redis-cache.html Configures go-redis/cache with a local in-process TinyLFU cache that stores 10,000 keys for 1 minute, in addition to the Redis backend. ```go mycache := cache.New(&cache.Options{ Redis: rdb, // Cache 10k keys for 1 minute. LocalCache: cache.NewTinyLFU(10000, time.Minute), }) ``` -------------------------------- ### Route readonly commands to slave nodes with NewFailoverClusterClient Source: https://redis.uptrace.dev/guide/go-redis-sentinel.html Experimental client that routes readonly commands to slave nodes. Enable RouteByLatency or RouteRandomly to choose routing strategy. Requires master name and Sentinel addresses. ```go import "github.com/redis/go-redis/v9" rdb := redis.NewFailoverClusterClient(&redis.FailoverOptions{ MasterName: "master-name", SentinelAddrs: []string{":9126", ":9127", ":9128"}, // To route commands by latency or randomly, enable one of the following. //RouteByLatency: true, //RouteRandomly: true, }) ``` -------------------------------- ### Connect over SSH with custom Dialer Source: https://redis.uptrace.dev/guide/go-redis.html Establishes an SSH connection and uses it as the dialer for Redis. Disables read/write timeouts because SSH does not support deadlines. ```go sshConfig := &ssh.ClientConfig{ User: "root", Auth: []ssh.AuthMethod{ssh.Password("password")}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: 15 * time.Second, } sshClient, err := ssh.Dial("tcp", "remoteIP:22", sshConfig) if err != nil { panic(err) } rdb := redis.NewClient(&redis.Options{ Addr: net.JoinHostPort("127.0.0.1", "6379"), Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { return sshClient.Dial(network, addr) }, // Disable timeouts, because SSH does not support deadlines. ReadTimeout: -1, WriteTimeout: -1, }) ``` -------------------------------- ### Use rdb.Pipelined to queue and execute commands Source: https://redis.uptrace.dev/guide/go-redis-pipelines.html Uses rdb.Pipelined to queue commands and automatically call Exec when the function exits. The command result is available only after the pipeline is executed. ```go var incr *redis.IntCmd cmds, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error { incr = pipe.Incr(ctx, "pipelined_counter") pipe.Expire(ctx, "pipelined_counter", time.Hour) return nil }) if err != nil { panic(err) } // The value is available only after the pipeline is executed. fmt.Println(incr.Val()) ``` -------------------------------- ### Check Redis port with telnet Source: https://redis.uptrace.dev/guide/go-redis.html Runs telnet to verify if Redis is listening on the port. The output shows a successful connection attempt and a connection refused error. ```bash telnet localhost 6379 Trying 127.0.0.1... telnet: Unable to connect to remote host: Connection refused ``` -------------------------------- ### Compare connection pooling in go-redis and redigo Source: https://redis.uptrace.dev/guide/go-redis-vs-redigo.html Highlights that go-redis handles connection pooling automatically, whereas redigo requires manual management. ```go // go-redis implicitly uses connection pooling _, err := rdb.Set(...).Result() // redigo requires explicit connection management conn := pool.Get() _, err := conn.Do(...) conn.Close() ``` -------------------------------- ### Set ServerName to fix x509 certificate validation error Source: https://redis.uptrace.dev/guide/go-redis.html Adds ServerName to tls.Config to resolve 'x509: cannot validate certificate for xxx.xxx.xxx.xxx because it doesn't contain any IP SANs'. ```go rdb := redis.NewClient(&redis.Options{ TLSConfig: &tls.Config{ MinVersion: tls.VersionTLS12, ServerName: "your.domain.com", }, }) ``` -------------------------------- ### Receive messages with pubsub.ReceiveMessage Source: https://redis.uptrace.dev/guide/go-redis-pubsub.html Receives messages in a loop. If an error occurs, it panics. Prints the channel and payload of each message. ```go for { msg, err := pubsub.ReceiveMessage(ctx) if err != nil { panic(err) } fmt.Println(msg.Channel, msg.Payload) } ``` -------------------------------- ### Subscribe to a channel with rdb.Subscribe Source: https://redis.uptrace.dev/guide/go-redis-pubsub.html Subscribes to a channel. go-redis automatically reconnects on error, so no error is returned. The subscription is closed with defer pubsub.Close(). ```go // There is no error because go-redis automatically reconnects on error. pubsub := rdb.Subscribe(ctx, "mychannel1") // Close the subscription when we are done. defer pubsub.Close() ``` -------------------------------- ### Define a Go struct with redis field tags Source: https://redis.uptrace.dev/guide/scanning-hash-fields.html Defines a Model struct with redis tags to map field names and ignore fields with `redis:"-"`. ```go type Model struct { Str1 string `redis:"str1"` Str2 string `redis:"str2"` Int int `redis:"int"` Bool bool `redis:"bool"` Ignored struct{} `redis:"-"` } ``` -------------------------------- ### Write a struct to Redis with HSet Source: https://redis.uptrace.dev/guide/scanning-hash-fields.html Uses HSet to write the fields of a struct into a Redis hash. ```go if err := rdb.HSet(ctx, "key", model1).Err(); err != nil { panic(err) } ``` -------------------------------- ### Cuckoo filter with CF.ADDNX, CF.EXISTS, and CF.DEL Source: https://redis.uptrace.dev/guide/bloom-cuckoo-count-min-top-k.html Use CF.ADDNX, CF.EXISTS, and CF.DEL commands to add, check, and delete items in a Cuckoo filter. The function demonstrates that Cuckoo filters support deletions, unlike Bloom filters. ```go func cuckooFilter(ctx context.Context, rdb *redis.Client) { inserted, err := rdb.Do(ctx, "CF.ADDNX", "cf_key", "item0").Bool() if err != nil { panic(err) } if inserted { fmt.Println("item0 was inserted") } else { fmt.Println("item0 already exists") } for _, item := range []string{"item0", "item1"} { exists, err := rdb.Do(ctx, "CF.EXISTS", "cf_key", item).Bool() if err != nil { panic(err) } if exists { fmt.Printf("%s does exist\n", item) } else { fmt.Printf("%s does not exist\n", item) } } deleted, err := rdb.Do(ctx, "CF.DEL", "cf_key", "item0").Bool() if err != nil { panic(err) } if deleted { fmt.Println("item0 was deleted") } } ``` -------------------------------- ### bunrouter middleware for HTTP rate limiting Source: https://redis.uptrace.dev/guide/go-redis-rate-limiting.html A bunrouter middleware that uses redis_rate to limit requests per minute. It sets RateLimit-Remaining and RateLimit-RetryAfter headers, and returns ErrRateLimited when the limit is exceeded. ```go func rateLimit(next bunrouter.HandlerFunc) bunrouter.HandlerFunc { return func(w http.ResponseWriter, req bunrouter.Request) error { res, err := limiter.Allow(req.Context(), "project:123", redis_rate.PerMinute(10)) if err != nil { return err } h := w.Header() h.Set("RateLimit-Remaining", strconv.Itoa(res.Remaining)) if res.Allowed == 0 { // We are rate limited. seconds := int(res.RetryAfter / time.Second) h.Set("RateLimit-RetryAfter", strconv.Itoa(seconds)) // Stop processing and return the error. return ErrRateLimited } // Continue processing as normal. return next(w, req) } } ``` -------------------------------- ### Instrument Redis client with redisotel Source: https://redis.uptrace.dev/guide/go-redis-monitoring.html Add the redisotel hook to a Redis client to enable tracing and metrics instrumentation. Works for redis.Client, redis.ClusterClient, and redis.Ring. ```go import ( "github.com/redis/go-redis/v9" "github.com/redis/go-redis/extra/redisotel/v9" ) rdb := redis.NewClient(&redis.Options{...}) // Enable tracing instrumentation. if err := redisotel.InstrumentTracing(rdb); err != nil { panic(err) } // Enable metrics instrumentation. if err := redisotel.InstrumentMetrics(rdb); err != nil { panic(err) } ``` -------------------------------- ### Pass active trace context to Redis commands Source: https://redis.uptrace.dev/guide/go-redis-monitoring.html To make tracing work, pass the active trace context to go-redis commands, as shown with req.Context(). ```go ctx := req.Context() val, err := rdb.Get(ctx, "key").Result() ``` -------------------------------- ### Iterate over set elements with SScan Source: https://redis.uptrace.dev/guide/get-all-keys.html Iterates over elements of a set named 'set-key' that match the pattern 'prefix:*' using SScan's iterator. ```Go iter := rdb.SScan(ctx, "set-key", 0, "prefix:*", 0).Iterator() ``` -------------------------------- ### Scan each master node in Redis Cluster or Ring Source: https://redis.uptrace.dev/guide/get-all-keys.html Scans each master node in Redis Cluster or Ring using rdb.ForEachMaster, iterating over keys with 'prefix:*' on each client. The provided callback is abbreviated; you would include the actual key iteration logic and return iter.Err(). ```Go err := rdb.ForEachMaster(ctx, func(ctx context.Context, rdb *redis.Client) error { iter := rdb.Scan(ctx, 0, "prefix:*", 0).Iterator() ... return iter.Err() }) if err != nil { panic(err) } ``` -------------------------------- ### Scan a subset of hash fields with HMGet Source: https://redis.uptrace.dev/guide/scanning-hash-fields.html Uses HMGet to scan only the specified fields into a Model struct. ```go var model2 Model // Scan a subset of the fields. if err := rdb.HMGet(ctx, "key", "str1", "int").Scan(&model2); err != nil { panic(err) } ``` -------------------------------- ### Set connection pool size in go-redis Source: https://redis.uptrace.dev/guide/go-redis-debugging.html Configures the Redis client pool size to 1000 connections. The default is 10 per CPU, and increasing it may help under high load, but it does not improve server or network speed. ```go rdb := redis.NewClient(&redis.Options{ PoolSize: 1000, }) ``` -------------------------------- ### Access command value and error separately Source: https://redis.uptrace.dev/guide/go-redis.html Saves the command object and later accesses the value and error separately using Val() and Err() methods. ```go get := rdb.Get(ctx, "key") fmt.Println(get.Val(), get.Err()) ``` -------------------------------- ### Check TCP FIN timeout setting Source: https://redis.uptrace.dev/guide/go-redis-debugging.html Displays the Linux TCP FIN timeout value, which is typically 60 seconds. This relates to TIME_WAIT state duration for closed connections. ```bash cat /proc/sys/net/ipv4/tcp_fin_timeout 60 ``` -------------------------------- ### Iterate over Redis keys using SCAN iterator Source: https://redis.uptrace.dev/guide/get-all-keys.html Simplifies SCAN iteration with the Iterator() method, which internally handles the cursor. It prints each key and checks for errors after the loop. ```Go iter := rdb.Scan(ctx, 0, "prefix:*", 0).Iterator() for iter.Next(ctx) { fmt.Println("keys", iter.Val()) } if err := iter.Err(); err != nil { panic(err) } ``` -------------------------------- ### Iterate over sorted set elements with ZScan Source: https://redis.uptrace.dev/guide/get-all-keys.html Iterates over elements of a sorted set named 'sorted-hash-key' that match the pattern 'prefix:*' using ZScan's iterator. ```Go iter := rdb.ZScan(ctx, "sorted-hash-key", 0, "prefix:*", 0).Iterator() ``` -------------------------------- ### Iterate over hash fields with HScan Source: https://redis.uptrace.dev/guide/get-all-keys.html Iterates over fields of a hash named 'hash-key' that match the pattern 'prefix:*' using HScan's iterator. ```Go iter := rdb.HScan(ctx, "hash-key", 0, "prefix:*", 0).Iterator() ``` -------------------------------- ### Redis config for cache storage Source: https://redis.uptrace.dev/guide/go-redis-cache.html Redis configuration for using Redis as a cache storage. Sets a memory limit of 100mb, uses allkeys-lfu eviction policy, enables active defragmentation, and disables disk persistence. ```redis # Required ########## # Set a memory usage limit to the specified amount of bytes. # When the memory limit is reached Redis will try to remove keys # according to the eviction policy selected (see maxmemory-policy). maxmemory 100mb # Optional ########## # Evict any key using approximated LFU when maxmemory is reached. maxmemory-policy allkeys-lfu # Enable active memory defragmentation. activedefrag yes # Don't save data on the disk because we can afford to lose cached data. save "" ``` -------------------------------- ### Delete Redis keys without TTL using SCAN Source: https://redis.uptrace.dev/guide/get-all-keys.html Iterates over all keys (no pattern) and deletes keys that have no TTL (TTL returns -1). Uses rdb.TTL to check and rdb.Del to remove. ```Go iter := rdb.Scan(ctx, 0, "", 0).Iterator() for iter.Next(ctx) { key := iter.Val() d, err := rdb.TTL(ctx, key).Result() if err != nil { panic(err) } if d == -1 { // -1 means no TTL if err := rdb.Del(ctx, key).Err(); err != nil { panic(err) } } } if err := iter.Err(); err != nil { panic(err) } ``` -------------------------------- ### Compare memory usage of Bloom and Cuckoo filters Source: https://redis.uptrace.dev/guide/bloom-cuckoo-count-min-top-k.html Reserve a Bloom filter and a Cuckoo filter, then check their memory usage. The output shows that the Bloom filter uses less memory (78080 bytes) than the Cuckoo filter (131160 bytes) for the same capacity. ```redis 127.0.0.1:6379> BF.RESERVE bloom_key 0.1 100000 OK 127.0.0.1:6379> MEMORY USAGE bloom_key (integer) 78080 127.0.0.1:6379> CF.RESERVE cf_key 100000 OK 127.0.0.1:6379> MEMORY USAGE cf_key (integer) 131160 ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.