Go Client Libraries for Redis

What is Go?

Go (also referred to as Golang) is a popular programming language known for its performance, simplicity and reliability. Given that they work so well together, it’s not a surprise that there are multiple open-source Go client libraries for Redis! Although that’s a good thing, having multiple choices implies that we need to put in thought when choosing a client to ensure it’s the right fit for our requirements.

Some of the common factors that we might take into consideration when picking a client library include:

  • Ease of use: Are we looking for a simple, intuitive API with a short learning curve?

  • Popularly and community support: Are we going to rely on the open-source community and library maintainers to help with queries, accept patches/updates/pull requests, fix issues, and so on?

  • Performance: If raw performance is what we’re after, then we need to carefully go through existing benchmarks and do testing as well.

With that said, let’s go through a quick overview of some of the Go clients for Redis. All of the libraries chosen for this course have over 500 stars on GitHub. This is not to suggest that number of stars is the only indicator of quality (or popularity), but it gives us a reasonable starting point.

The following Redis clients will be covered in this lesson:

  • go-redis

  • redigo

  • rueidis

The go-redis client

The go-redis client is one of the most popular clients with more than 15,500 stars (at the time of writing). In addition to support for all core Redis data types, it has the following:

  • Support for Redis 7 features.

  • Great documentation.

  • Support for instrumentation via OpenTelemetry.

  • A good ecosystem of features, including Redis-based distributed lock and rate limiter implementations.

Note: The go-redis client will be used for the majority of the lessons in this course, unless otherwise noted.

Code sample

Here’s a code snippet to give a general sense of how it works:

client := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
ctx := context.Background()
err := client.Ping(context.Background()).Err()
if err != nil {
log.Fatal(err)
}
defer client.Close()
client.Set(ctx, "go-redis", "github.com/go-redis/redis", 0)
log.Println("go-redis repo", client.Get(ctx, "go-redis").Val())
  • Line 1: To get a client handle (redis.Client) for a Redis server, use the redis.NewClient function. Note that this does not actually establish the connection, so it’s a good idea to use Ping (line 4) to ensure you have actually connected successfully.

  • Lines 12–13: Once that’s done, all the operations (Set, Get, etc.) can be invoked from the redis.Client instance.

The go-redis API is quite intuitive, the library is stable, active, and has a fairly active community. It’s the recommended library if you’re building Redis applications with Go.

The redigo client

The redigo client is a fairly stable and tenured client that supports all the standard Redis data types and features such as transactions, pipelining, etc. It’s also used to implement other Go client libraries like redisearch-go and the Redis TimeSeries Go client.

Note: The redigo client doesn’t support Redis Cluster.

Code sample

Here’s a code snippet to give a general sense of how it works:

c, err := goredis.Dial("tcp", "localhost:6379")
if err != nil {
log.Fatal(err)
}
defer c.Close()
c.Do("SET", "redigo", "github.com/gomodule/redigo/redis")
s, _ := goredis.String(c.Do("GET", "redigo"))
log.Println("redigo repo", s)
  • Line 1: The Dial function is used to establish connectivity and returns a redis.Conn instance.

  • Line 8: After that, we use the Do function to create the appropriate commands. In this example, we use SET and GET.

With such an API, we lose strong typing; however, it provides flexibility. This flexibility makes it possible to implement features for new Redis versions without having to wait for the client to implement the code (although the implementation efforts depend on the command’s complexity).

The rueidis client

The rueidis client is a relatively new and quickly evolving client library. It supports RESP3 protocol, client-side caching, and a variety of Redis modules, such as RedisJSON, RedisBloom, RediSearch, RedisGraph, RedisTimeSeries, RedisAI, and RedisGears. It also has a generic hash or the RedisJSON object mapping capability for OpenTelemetry support of tracing and metrics.

Code sample

Here’s a code snippet to give a general sense of how it works:

c, err := rueidis.NewClient(rueidis.ClientOption{
InitAddress: []string{"localhost:6379"},
})
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
c.Do(ctx, c.B().Set().Key("rueids").Value("github.com/rueian/rueidis").Nx().Build()).Error()
r, _ := c.Do(ctx, c.B().Get().Key("rueids").Build()).ToString()
log.Println("rueidis repo", r)

The rueidis client adopts an interesting approach.

Line 10: Like the redigo client, it provides a Do function, but the way it creates the command is through a Builder function—this retains strong type checking, unlike the redigo client.

Connecting to Redis with different Go clients

Here’s the complete code for connecting to Redis using all the Go clients mentioned above. Click the “Run” button to execute the code.

package main
import (
"context"
"log"
"github.com/go-redis/redis/v8"
goredis "github.com/gomodule/redigo/redis"
"github.com/rueian/rueidis"
)
func main() {
goredisClient()
redigoClient()
rueidsClient()
}
//example for goredis client
func goredisClient() {
client := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
ctx := context.Background()
//ping redis
err := client.Ping(context.Background()).Err()
if err != nil {
log.Fatal(err)
}
defer client.Close()
log.Println("using go-redis client")
//set value for a key
client.Set(ctx, "go-redis", "github.com/go-redis/redis", 0)
log.Println("executed SET")
//get value for the key
r := client.Get(ctx, "go-redis").Val()
log.Println("executed GET")
log.Println("value for go-redis", r)
}
//example for redigo client
func redigoClient() {
//establish connection to redis
c, err := goredis.Dial("tcp", "localhost:6379")
if err != nil {
log.Fatal(err)
}
defer c.Close()
log.Println("using redigo client")
//set value for a key
c.Do("SET", "redigo", "github.com/gomodule/redigo/redis")
log.Println("executed SET")
//get value for the key
s, _ := goredis.String(c.Do("GET", "redigo"))
log.Println("executed GET")
log.Println("value for redigo =", s)
}
//example for rueids client
func rueidsClient() {
//create new redis client instance
c, err := rueidis.NewClient(rueidis.ClientOption{
InitAddress: []string{"localhost:6379"},
})
if err != nil {
log.Fatal(err)
}
defer c.Close()
ctx := context.Background()
log.Println("using rueidis client")
//set value for a key
c.Do(ctx, c.B().Set().Key("rueids").Value("github.com/rueian/rueidis").Nx().Build()).Error()
log.Println("executed SET")
//get value for the key
r, _ := c.Do(ctx, c.B().Get().Key("rueids").Build()).ToString()
log.Println("executed GET")
log.Println("value for rueidis =", r)
}

The output represents the GET and SET operations being executed by different Go clients that we discussed earlier in this lesson. First is the go-redis client, followed by redigo, and finally, we have the rueidis client.