Remote dictionary service (redis) is an in-memory key-value data structure store used as a cache/database. Generally, it used as a cache in front of another persistent database to speed up application performance.

Redis provides in-built support for various data structures such as

  • strings
  • hashes
  • lists
  • sets
  • sorted sets with range queries
  • bitmaps
  • hyperloglogs
  • geospatial indexes
  • streams

Architecture

An overview of redis architecture is available at architecturenotes

Install on Ubuntu

Refer to official redis docs

Golang Client

Redis office site list various redis clients here. I decided to try out Redigo

Create a RedisPool

Create a redispool object using following code

package redispool

import (
	"fmt"
	"os"
	"time"

	"github.com/gomodule/redigo/redis"
)

// default redis TCP port
const defaultRedisPort = 6379

// RedisServer ... redis server to connect to
var RedisServer = func() string {
	// $REDIS_SERVER takes precedence
	server := os.Getenv("REDIS_SERVER")
	if server == "" {
		// otherwise use the localhost:6379
		server = fmt.Sprintf("localhost:%d", defaultRedisPort)
	}
	return server
}()

// RedisPool ... redis connection pool
var RedisPool = redis.Pool{
	// check the health of an idle connection before the connection is used again
	TestOnBorrow: testIdleConn,
	MaxIdle:      2,               // Maximum number of idle connections in the pool
	IdleTimeout:  2 * time.Minute, // Close connections after remaining idle for this duration.
	Dial:         dialRedis,
}

func testIdleConn(c redis.Conn, _ time.Time) error {
	fmt.Println("Ping connection")
	reply, err := c.Do("Ping")
	fmt.Printf("TestOnBorrow :: Redis reply %v\n", reply)
	return err
}

func dialRedis() (redis.Conn, error) {
	c, err := redis.Dial("tcp", RedisServer)
	if err != nil {
		fmt.Printf("Dial (%s) failed: %v\n", RedisServer, err)
		return nil, err
	}

	fmt.Printf("opened redis connection to %s\n", RedisServer)
	return c, nil
}

Check Connection to redis server

Use the following code to check connection

package main

import (
	"fmt"

	"github.com/manoj-gupta/cloud/redispool"
)

func main() {
	conn := redispool.RedisPool.Get()
	defer func() {
		fmt.Printf("closing redis connection to %s\n", redispool.RedisServer)
		conn.Close()
	}()
}

Running the program should generate output

$ go run redispool/app/main.go 
opened redis connection to localhost:6379
closing redis connection to localhost:6379

Test GET/SET

Add the following code in main.go to see how GET and SET works for basic data types

	if _, err := conn.Do("SET", stringKey, "Hello Redis"); err != nil {
		fmt.Printf("Can not update %s err:%v\n", stringKey, err)
		os.Exit(1)
	}

	if val, err := redis.String(conn.Do("GET", stringKey)); err != nil {
		fmt.Printf("Can not read %s err:%v\n", stringKey, err)
		os.Exit(1)
	} else {
		fmt.Printf("READ Success --> key:%s val:%s\n", stringKey, val)
	}

Running the program should generate the output

$ go run redispool/app/main.go 
opened redis connection to localhost:6379
READ Success --> key:redis-string-key val:Hello Redis
closing redis connection to localhost:6379