How to use Golang as Redis Client? [SOLVED]


GO

Reviewer: Deepak Prasad

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

  1. Setting up Go and redis
  2. Connect to redis  using Go
  3. Store and retrieve  data from redis

 

Prerequisite

  1. Go installed
  2. Redis server is installed
  3. 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

 

Antony Shikubu

Antony Shikubu

He is highly skilled software developer with expertise in Python, Golang, and AWS cloud services. Skilled in building scalable solutions, he specializes in Django, Flask, Pandas, and NumPy for web apps and data processing, ensuring robust and maintainable code for diverse projects. You can reach out to him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment