Introduction
Go is statically typed , compiled high level programming language designed to improve programming productivity, and is majorly being used to create distributed network services, cloud native development, and development of web servers. On the other hand , redis is an open source in-memory data store used as database , cache and message broker. It provides and supports data structures such as strings, lists, sets, sorted sets , streams and many more.
Go and redis can be used to develop robust systems/applications and in this article, you will learn how to get started with Go and redis by
- Setting up Go and redis
- Connect to redis using Go
- Store and retrieve data from redis
Prerequisite
- Go installed
- Redis server is installed
- Code editor
In this article we assume that you already have a working Redis Server. We have already covered the steps to install and configure Redis on Rcky Linux 9. You can follow the same and then start with this tutorial.
Setting up Go redis project
In this section , you will set up a simple Go program and run it. You will create the main.go file and initialize a go module. Navigate to your working directory and issue the below command using the terminal. Follow the steps below to get started.
Create a working directory and navigate into it.
mkdir go-redis-app && cd go-redis-app
Create the main.go
file
touch main.go
Initialize a go module
go mod init example.com/go-redis-app
Connecting to Redis Server using Go
To be able to interact with redis using Go, you need a redis client.In this example, you will use Go-redis, a type-safe, a redis client library for Go. To install the redis client library, issue the below command in the terminal.
# go get github.com/redis/go-redis
go: finding module for package github.com/go-redis/redis
go: found github.com/go-redis/redis in github.com/go-redis/redis v6.15.9+incompatible
go: finding module for package github.com/onsi/ginkgo
go: downloading github.com/onsi/ginkgo v1.16.5
go: finding module for package github.com/onsi/gomega
go: downloading github.com/onsi/gomega v1.26.0
go: found github.com/onsi/ginkgo in github.com/onsi/ginkgo v1.16.5
go: found github.com/onsi/gomega in github.com/onsi/gomega v1.26.0
go: downloading github.com/google/go-cmp v0.5.9
go: downloading github.com/nxadm/tail v1.4.8
go: downloading gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
go: downloading golang.org/x/text v0.6.0
go: downloading github.com/fsnotify/fsnotify v1.4.9
Next you will write code to connect to redis. In the main.go
file add below code.
package main
import (
"fmt"
"github.com/go-redis/redis"
)
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "abcd1234", // provide your redis server password
DB: 0, // use default database
})
err := client.Ping().Err()
if err != nil {
fmt.Println("Redis is not working:", err)
return
}
fmt.Println("Redis is working.")
}
In this example, a Redis client is created using the redis.NewClient
function, and the Ping
method is used to check the connection to the Redis server. If the connection is successful, the Ping
method will return a nil error, and the message "Redis is working." will be printed. If there is an error, the message "Redis is not working" and the error message will be printed.
Here we will run one attempt with wrong password which is when we get NOAUTH Authentication required
. Later we re-execute main.go
with correct password and we get Redis is working
.
# go run main.go Redis is not working: NOAUTH Authentication required. # go run main.go Redis is working.
Create a new DB and add key value pair into DB
To store and retrieve data from the redis database, the Go redis client provides the Set()
and Get()
methods. To set a value , you need two pieces of data, the key and the value to set. The key can later be used to retrieve the value as shown below.
package main
import (
"fmt"
"github.com/go-redis/redis"
)
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "abcd1234", // provide password of redis server
DB: 1, // use database 1
})
err := client.Ping().Err()
if err != nil {
fmt.Println(err)
return
}
// Set a key-value pair
err = client.Set("key", "value", 0).Err()
if err != nil {
fmt.Println(err)
return
}
// Get the value of a key
value, err := client.Get("key").Result()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("value:", value)
}
In this example, the Redis client is created using the redis.NewClient
function, and the database to be used is specified in the Options
struct as the DB
field. The Ping
method is used to verify the connection, and the Set
method is used to set a key-value pair. The Get
method is used to retrieve the value of a key.
Output:
# go run main.go
value: value
Create a DB to store user information
In this example, a Redis client is created using the redis.NewClient
function, and the connection is verified using the Ping
method. The HMSet
method is used to add a user to the database as a hash, with the user's information stored as fields in the hash. The HMGet
method is used to retrieve the user information, and the Result
method is used to get the values of the fields in the hash.
package main
import (
"fmt"
"github.com/go-redis/redis"
)
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "abcd1234", // password for redis server
DB: 0, // use default database
})
err := client.Ping().Err()
if err != nil {
fmt.Println("Error connecting to Redis:", err)
return
}
// Add a user to the database
err = client.HMSet("user:1", map[string]interface{}{
"username": "amitkumar",
"employeeNumber": "12345",
"email": "amitkumar@example.com",
"address": "123 Some St.",
}).Err()
if err != nil {
fmt.Println("Error adding user 1:", err)
return
}
// Add another user to the database
err = client.HMSet("user:2", map[string]interface{}{
"username": "rahulkumar",
"employeeNumber": "67890",
"email": "rahulkumar@example.com",
"address": "456 Some St.",
}).Err()
if err != nil {
fmt.Println("Error adding user 2:", err)
return
}
// Retrieve user 1 from the database
result, err := client.HMGet("user:1", "username", "employeeNumber", "email", "address").Result()
if err != nil {
fmt.Println("Error retrieving user 1:", err)
return
}
fmt.Println("User 1 information:")
fmt.Println("Username:", result[0])
fmt.Println("Employee Number:", result[1])
fmt.Println("Email:", result[2])
fmt.Println("Address:", result[3])
// Retrieve user 2 from the database
result, err = client.HMGet("user:2", "username", "employeeNumber", "email", "address").Result()
if err != nil {
fmt.Println("Error retrieving user 2:", err)
return
}
fmt.Println("User 2 information:")
fmt.Println("Username:", result[0])
fmt.Println("Employee Number:", result[1])
fmt.Println("Email:", result[2])
fmt.Println("Address:", result[3])
}
Output:
# go run main.go User 1 information: Username: amitkumar Employee Number: 12345 Email: amitkumar@example.com Address: 123 Some St. User 2 information: Username: rahulkumar Employee Number: 67890 Email: rahulkumar@example.com Address: 456 Some St.
Insert additional data into existing Redis DB
In this example we add another user into our existing DB which we had used in our previous step to add user1
and user2
. Later we will also fetch the user information from the DB:
package main
import (
"fmt"
"github.com/go-redis/redis"
)
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "abcd1234", // provide password for redis server
DB: 0, // use default database
})
err := client.Ping().Err()
if err != nil {
fmt.Println("Error connecting to Redis:", err)
return
}
// Add user3 to the database
err = client.HMSet("user:3", map[string]interface{}{
"username": "ravikumar",
"employeeNumber": "11111",
"email": "ravikumar@example.com",
"address": "789 Some St.",
}).Err()
if err != nil {
fmt.Println("Error adding user 3:", err)
return
}
// Retrieve user3 from the database
result, err := client.HMGet("user:3", "username", "employeeNumber", "email", "address").Result()
if err != nil {
fmt.Println("Error retrieving user 3:", err)
return
}
fmt.Println("User 3 information:")
fmt.Println("Username:", result[0])
fmt.Println("Employee Number:", result[1])
fmt.Println("Email:", result[2])
fmt.Println("Address:", result[3])
}
Output:
# go run main.go
User 3 information:
Username: rahulkumar
Employee Number: 67890
Email: rahulkumar@example.com
Address: 456 Some St.
Implement in-memory cache with Redis Server
Example-1: Provide a timeout threshold for the cache entry
Here's an example that demonstrates how to store data in an in-memory cache and assign a timeout:
package main
import (
"fmt"
"time"
"github.com/go-redis/redis"
)
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "abcd1234", // password for redis server
DB: 0, // use default DB
})
err := client.Set("key", "value", time.Minute).Err()
if err != nil {
panic(err)
}
val, err := client.Get("key").Result()
if err != nil {
panic(err)
}
fmt.Println("key", val)
time.Sleep(time.Minute + time.Second)
val, err = client.Get("key").Result()
if err == redis.Nil {
fmt.Println("key does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("key", val)
}
}
In this example, the data is stored in Redis with a timeout of 1 minute using the Set
method. After the sleep of 1 minute and 1 second, the data is retrieved using the Get
method and we check if the key still exists or not. If the key no longer exists, the Get
method returns an error with a value of redis.Nil
, indicating that the key does not exist.
Output:
# go run main.go
key value
key does not exist
Example-2: Define cache limit and automatically clear cache when it reaches limit
We can also define a size for cache and as soon it is full, the last element is automatically removed from the cache.
package main
import (
"fmt"
"strconv"
"github.com/go-redis/redis"
)
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "abcd1234",
DB: 0,
})
// Define the cache size
const cacheSize = 3
keys, err := client.Keys("key-*").Result()
if err != nil {
panic(err)
}
fmt.Println("Existing keys:", keys)
for i := 0; i < 5; i++ {
key := "key-" + strconv.Itoa(i)
err = client.Set(key, i, 0).Err()
if err != nil {
panic(err)
}
fmt.Println("Inserted key", i)
// Get the length of the cache
len, err := client.DBSize().Result()
if err != nil {
panic(err)
}
// If the cache is full, remove the last element
if len >= cacheSize {
val, err := client.RPop("key-list").Result()
if err != nil {
panic(err)
}
err = client.Del(val).Err()
if err != nil {
panic(err)
}
fmt.Println("Removed key", val)
}
err = client.LPush("key-list", key).Err()
if err != nil {
panic(err)
}
}
}
In this example, we use the DBSize
method to retrieve the length of the cache, and the RPop
and RPush
methods to manage a list of keys. When the cache is full, we use the RPop
method to remove the last key from the list and the Del
method to remove the key-value pair from the cache. This way, we ensure that the cache always stays within the defined size limit and the last element is automatically removed if the cache is full.
Output:
# go run main.go
Existing keys: [key-2 key-3 key-4 key-list]
Inserted key 0
Removed key key-2
Inserted key 1
Removed key key-3
Inserted key 2
Removed key key-4
Inserted key 3
Removed key key-0
Inserted key 4
Removed key key-1
Summary
In this article you learn to use the Go programming language to write and read data from the redis database. Before writing and reading data from the database, the redis server should be running , be it in a container, or in a local redis server. Without which no data operation can be performed. Redis can also be used for data caching and as a message broker. This article focuses mainly on writing and reading data from the redis server.
To learn more about redis and perform CRUD operations, you can read the Building a CRUD REST API using Redis DB in Go.Â
References
https://github.com/redis/go-redis