onemuri.space

go で redis を使う


go で redis を使うときは、 go-redis や、 redigo があります。 Redis の 公式サイト でも紹介されています。

今回は軽く go-redis を使って redis を扱ってみます。

go-redis install

go get github.com/go-redis/redis/v8

最新の version は 公式 をみてください。今回は執筆時点で最新の v8 をインストールします。

go-redis で redis client を生成します。

redis.NewClient(&redis.Options{
    Addr:     "localhost:6379",
    Password: "",
    DB:       0,
})

DB というオプションは redis における DB の番号です。デフォルトで、 0 ~ 15 の 16個分の番号を使うことができます。今回は何も考えずに 0 を使います。

set

redis client を作成したら早速 kvs に値をセットしてみましょう。

func setKey(ctx context.Context) error {
	if err := rClient.Set(ctx, "key", "value", 10*time.Second).Err(); err != nil {
		return err
	}
	return nil
}

value は interface{} でセットすることができます。

get

先ほどセットした key から値を取得してみましょう。とっても簡単ですね、これだけです。

func getKey(ctx context.Context) (string, error) {
	res, err := rClient.Get(ctx, "key").Result()
    if err != nil {
        return "", err
    }
	return res, nil
}

value は string で取得するので、もし構造体にマッピングする場合には json.Unmarshal する必要があります。

サンプルコード

今回はシンプルなコードで cache の際のレスポンス速度を体感できるようなサンプルコードを用意しました。

package main

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
)

var rClient *redis.Client

func init() {
	rClient = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})
}

func main() {
	e := gin.New()
	e.GET("", getKey)

	e.Run("localhost:8080")
}

func getKey(c *gin.Context) {
	ctx := c.Request.Context()
	res, err := getCachedKey(ctx, "key")
	if err != nil {
		c.JSON(http.StatusInternalServerError, err)
		return
	}
	c.JSON(http.StatusOK, res)
}

func getCachedKey(ctx context.Context, key string) (string, error) {
	res, err := rClient.Get(ctx, key).Result()
	switch err {
	case nil:
		break
	case redis.Nil:
		if err := setKey(ctx); err != nil {
			return "", err
		}
	default:
		return "", err
	}
	return res, nil
}

func setKey(ctx context.Context) error {
	sum := 0
	for i := 0; i < 3; i++ {
		time.Sleep(100 * time.Millisecond)
		sum += i
	}
	value := fmt.Sprintf("value: %d", sum)
	if err := rClient.Set(ctx, "key", value, 10*time.Second).Err(); err != nil {
		return err
	}
	return nil
}

上記のコードで、 curl localhost:8080 を叩くと cache されていない状態で、 70ms ほどかかりますが、一度叩いてから 10sec 経ってcache が clear されるまでは 10ms 以下でレスポンスが帰ってくると思います。

まとめ

redis の関数( Get()Set() )を wrap させることで汎用的に使いやすくすることができます。また構造体のmarshal / unmarshal も設定することでより使い勝手が良くなります。

redis とりあえず使ってみたい場合はぜひコピペでも良いので、感触を試してみるというのはどうでしょうか。

自己紹介用画像

Riki Akagi

2019年からDeNAで働いています。GCP(CloudSQL・GAE・Cloud Function etc)とGoでAPI開発に勤んでいます。睡眠やエンジニアリングに関することに興味を持って過ごしているのでその情報を皆さんに共有していけたらなと思っています。

自己紹介の詳細