Getting started with Golang Redis
Installation
go-redis supports 2 last Go versions and only works with Go modules. So first you need to initialize a Go module:
go mod init github.com/my/repo
To install go-redis/v9:
go get github.com/redis/go-redis/v9
Connecting to Redis Server
To connect to a Redis Server:
import "github.com/redis/go-redis/v9"
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
Another popular way is using a connection string:
opt, err := redis.ParseURL("redis://<user>:<pass>@localhost:6379/<db>")
if err != nil {
panic(err)
}
rdb := redis.NewClient(opt)
Using TLS
To enable TLS/SSL, you need to provide an empty tls.Config
. If you're using private certs, you need to specify them in the tls.Config
.
rdb := redis.NewClient(&redis.Options{
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
//Certificates: []tls.Certificate{cert}
},
})
If you are getting x509: cannot validate certificate for xxx.xxx.xxx.xxx because it doesn't contain any IP SANs
, try to set ServerName
option:
rdb := redis.NewClient(&redis.Options{
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
ServerName: "your.domain.com",
},
})
Over SSH
To connect over SSH channel:
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,
})
dial tcp: i/o timeout
You get dial tcp: i/o timeout
error when go-redis can't connect to the Redis Server, for example, when the server is down or the port is protected by a firewall. To check if Redis Server is listening on the port, run telnet command on the host where the go-redis client is running:
telnet localhost 6379
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
If you use Docker, Istio, or any other service mesh / sidecar, make sure the app starts after the container is fully available, for example, by configuring healthchecks with Docker and holdApplicationUntilProxyStarts
with Istio.
Context
Every Redis command accepts a context that you can use to set timeouts or propagate some information, for example, tracing context.
ctx := context.Background()
Executing commands
To execute a command:
val, err := rdb.Get(ctx, "key").Result()
fmt.Println(val)
Alternatively you can save the command and later access the value and the error separately:
get := rdb.Get(ctx, "key")
fmt.Println(get.Val(), get.Err())
Executing unsupported commands
To execute arbitrary/custom command:
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))
Do
returns a Cmd that has a bunch of helpers to work with interface{}
value:
// Text is a shortcut for get.Val().(string) with proper error handling.
val, err := rdb.Do(ctx, "get", "key").Text()
fmt.Println(val, err)
The full list of helpers:
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()
redis.Nil
go-redis exports the redis.Nil
error and returns it whenever Redis Server responds with (nil)
. You can use redis-cli to check what response Redis returns.
In the following example we use redis.Nil
to distinguish an empty string reply and a nil reply (key does not exist):
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")
}
GET
is not the only command that returns nil reply, for example, BLPOP
and ZSCORE
can also return redis.Nil
.
Conn
Conn represents a single Redis connection rather than a pool of connections. Prefer running commands from Client unless there is a specific need for a continuous single Redis connection.
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)