15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GoでRedisをかるーくいじってみた

Posted at

はじめに

n番煎じかと思いますが,自分の知識整理もかねてまとめてみました.
Golang で Redis をさくさくいじってみます.本記事では Docker のインストール済みを想定しています.

環境は以下

  • macOS (ver 10.14)
  • Docker (ver 19.3.1)
  • Golang (ver 1.12.7)

ざっくりRedisとは

  • 永続化可能なインメモリデータベース
  • KVS(Key Value Store)
  • 5つのデータ型をサポート
    • string / hash / list / set / sorted set

利点とは

  • 高速
  • シングルスレッドなので,必然的に処理が排他的になる
  • データの生存期間(TTL)が設定できる
  • ランキングの扱い
    • ソートをやってくれるデータ構造があるので.

参考

Redisについては,こちらの記事がすごく丁寧なのでぜひ.
データ構造やコマンドについては,TryRedisをやってみると感覚がつかみやすい気がします.

Redis を構築

まず Docker で Redis の準備を行います.
Docker Image はこちらを使います.

$ docker run --name redis -d -p 6379:6379 redis redis-server --appendonly yes

Redis をローカルにインストール.
(Go で Redis にアクセスできているか確認するときなどに使います.)

$ brew install redis

以下のようになればOK

$ redis-cli
127.0.0.1:6379> 

redisのコマンドをいくつか試してみます.

// key を全て取得
127.0.0.1:6379> KEYS *
(empty list or set)

// SET key value
127.0.0.1:6379> SET test-key test-val
OK

127.0.0.1:6379> KEYS *
1) "test-key"

// key の削除
127.0.0.1:6379> DEL test-key
(integer) 1

127.0.0.1:6379> KEYS *
(empty list or set)

127.0.0.1:6379> exit

Go で Redis を触ってみる

いよいよ本題.Go で Redis を軽く触っていきます.
redigo というパッケージを使用します.

redigo のインストール

go get github.com/gomodule/redigo/redis

実際にやってみる

  • データの登録と取得
redis.go
package main

import(
    "fmt"
    
    "github.com/gomodule/redigo/redis"
)

// Connection
func Connection() redis.Conn {
    const Addr = "127.0.0.1:6379"
    
    c, err := redis.Dial("tcp", Addr)
    if err != nil {
        panic(err)
    }
    return c
}

// データの登録(Redis: SET key value)
func Set(key, value string, c redis.Conn) string{
    res, err := redis.String(c.Do("SET", key, value))
    if err != nil {
        panic(err)
    }
    return res
}

// データの取得(Redis: GET key)
func Get(key string, c redis.Conn) string {
    res, err := redis.String(c.Do("GET", key))
    if err != nil {
        panic(err)
    }
    return res
}

func main() {
    // 接続
    c := Connection()
    defer c.Close()
    
    // データの登録(Redis: SET key value)
    res_set := Set("sample-key", "sample-value", c)
    fmt.Println(res_set) // OK
    
    // データの取得(Redis: GET key)
    res_get := Get("sample-key", c)
    fmt.Println(res_get) // sample-value
}
実行結果:
$ go run redis.go
OK
sample-value

Redis: 
127.0.0.1:6379> KEYS *
1) "sample-key"

基本的に Redis のコマンドを実行したいタイミングで,Do()を呼び出す.
Do()の戻り値は,interface{}errorなので,型変換をする際は,redis.String()を呼び出す.
パッケージのコードをみた感じだと,intfloat64byteなどへの変換ができそう.呼び出し方は例によってredis.Int()など.

  • 複数の値を同時に登録,取得.かつ TTL をつけてみる
redis.go
package main

import(
    "fmt"
    
    "github.com/gomodule/redigo/redis"
)

// Connection
func Connection() redis.Conn {
    const Addr = "127.0.0.1:6379"
    
    c, err := redis.Dial("tcp", Addr)
    if err != nil {
        panic(err)
    }
    return c
}

type Data struct {
    Key string
    Value string
}

// 複数のデータの登録(Redis: MSET key [key...])
func Mset(datas []Data, c redis.Conn){
    var query []interface{}
    for _, v := range datas {
        query = append(query, v.Key, v.Value)
    }
    fmt.Println(query) // [key1 value1 key2 value2]
    
    c.Do("MSET", query...)
}

// 複数の値を取得 (Redis: MGET key [key...])
func Mget(keys []string, c redis.Conn) []string{
    var query []interface{}
    for _, v := range keys {
        query = append(query, v)
    }
    fmt.Println("MGET query:", query) // [key1 key2]
    
    res, err := redis.Strings(c.Do("MGET", query...))
    if err != nil {
        panic(err)
    }
    return res
}

// TTLの設定(Redis: EXPIRE key ttl)
func Expire(key string, ttl int, c redis.Conn) {
    c.Do("EXPIRE", key, ttl)
}

func main() {
    // 接続
    c := Connection()
    defer c.Close()
    
    // 複数データの登録
    datas := []Data{
        Data{Key:"key1", Value:"value1"},
        Data{Key:"key2", Value:"value2"},
    }
    Mset(datas, c)
    
    // 複数データの取得
    keys := []string{"key1", "key2"}
    res_mget := Mget(keys, c)
    fmt.Println(res_mget)
    
    // TTLの設定
    Expire("key1", 10, c)
}
実行結果:
$ go run redis.go
MSET query: [key1 value1 key2 value2]
MGET query: [key1 key2]
[value1 value2]

Redis:
127.0.0.1:6379> KEYS *
1) "sample-key"
2) "key2"
3) "key1"

Redis(10秒以上後):
127.0.0.1:6379> KEYS *
1) "sample-key"
2) "key2"

結果として複数の値を得る場合(今回はMGET),型変換を行う場合はredis.Strings()のように末尾にsがきます.他の型でも同様,redis.Intsなど.
TTLの設定については,秒単位で設定を行うEXPIREと,ミリ秒単位で設定を行うPEXPIREがある.

Redis から TTL の確認は,TTL keyで行う.

127.0.0.1:6379> TTL key1
(integer) 4

127.0.0.1:6379> TTL key1
(integer) -2

127.0.0.1:6379> TTL key2
(integer) -1

結果については以下のようになる.

  • 0以上:残りのTTL
  • -1 :TTLが設定されていない場合
  • -2 :key が存在しない場合

終わりに

ここまで読んでいただきありがとうございます!
あまり長くなってしまっても,同じことの繰り返しになってしまう部分も多いのでこの辺りで.
パッケージのコードをみていたら,Do()の結果をmapに格納できる雰囲気が....まだまだ学べそうです.
コードや解釈の間違いなどありましたら,指摘していただけると幸いです.

15
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?