LoginSignup
49
35

More than 5 years have passed since last update.

【Redis】Go言語で高速呼び出しKVS【Redigo】

Last updated at Posted at 2018-02-07

始めに

Go言語のORMが少しずつのびてきているので、次はKVSであるRedisをGo言語で触ってみようと思います。

たまにデータベースからの呼び出しの遅さがボトルネックになることに。
これをKVSの導入によって解消!みたいな感じです。

実践!

環境

  • golang ver1.4.2
  • Redis ver3.2.4
  • EC2

EC2に導入

EC2にRedisをインストールしてみます。

インストール

sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
sudo yum --enablerepo=remi install redis

サーバー起動

$ sudo service redis start

これでサーバーが起動したはず、、、

以下のコマンドで対話式に確認ができる。

$ redis-cli

スクリーンショット 2018-02-08 0.24.34.png

ちゃんと起動出来ていると、

$ 127.0.0.1/6379>

と表示される。

上の画像では

$ 127.0.0.1/6379> get "hoge"
<nil>

で"hoge"っていうkeyのvalueをよこせ!って言ってる。

当然、何も記憶させていないからnilが返ってくる。

そこで、

$ 127.0.0.1/6379> set "hoge" "bell"
OK
$ 127.0.0.1:6379> get "hoge"
"bell"

setで"hoge"というkeyに対して"bell"っていうvalueが保存できた。

改めて、get "hoge"でvalueを呼び出すと保存した"bell"が帰ってきた。



これでEC2へのRedisのインストールは完了!

今度はこれをGoで操作していきます

RedisをGo言語で。Redigo。

必要なパッケージ

github.com/garyburd/redigo/redis

これだけ(笑)

go get github.com/garyburd/redigo/redis

redisとの接続

まずはEC2にインストールしたRedisと接続を確立します。

func redis_connection() redis.Conn {
  const IP_PORT = "52.###.55.###:6379"

  //redisに接続
  c, err := redis.Dial("tcp", IP_PORT)
  if err != nil {
    panic(err)
  }
  return c
}

接続には以下の要素が必要になります。

  • プロトコル:tcp
  • IPアドレス:52.###.55.###
  • ポート番号:6379(デフォルト設定)

IPアドレスはredisがインストールされているサーバーのIPアドレスで、ポート番号はデフォルト設定されてるものでは6379が使用されているはずです。

接続が確立されている場合、errにはnilが返ります。逆に接続が確立されていない場合は、errにnilが返らずにエラー検出の部分でエラーが出ます。

ちなみに、redis.Connはreturnする値の型を指定していてredisとのコネクションを表すcのデータ型を表しています。

SETとGET

接続ができたら実際に値を入れて、取ってくる動作を実装します。

これは、上記のようにコマンドで行ったやり取りとほぼ同様です。

func redis_set(key string, value string, c redis.Conn){
  c.Do("SET", key, value)
}

まずはSETです、これはRedisにkeyとvalueを格納する動作になります。

見て分かる通り、コネクションcのDo関数を使います。
次にGETです。

func redis_get(key string, c redis.Conn) string{
  s, err := redis.String(c.Do("GET", key))
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  return s
}

第一引数に"GET"を渡して、取り出したいvalueのkeyを渡します。

redis.String()でstring型になります。

この2つが使えれば、基本的なRedisの扱いは大丈夫だと思います。

一応、以下サンプルコードです。

go-redis.go
package main

import (
  "github.com/garyburd/redigo/redis"
  "fmt"
  "os"
)

func redis_set(key string, value string, c redis.Conn){
  c.Do("SET", key, value)
}

func redis_get(key string, c redis.Conn) string{
  s, err := redis.String(c.Do("GET", key))
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  return s
}

func redis_connection() redis.Conn {
  const IP_PORT = "52.###.55.###:6379"

  //redisに接続
  c, err := redis.Dial("tcp", IP_PORT)
  if err != nil {
    panic(err)
  }
  return c
}

func main() {
  c := redis_connection()
  defer c.Close()

  var key = "KEY"
  var val = "VALUE"
  redis_set(key, val, c)
  s := redis_get(key, c)
  fmt.Println(s)
}

Redisで確認

Redisに登録されているkeyやvalueを確認したい時ありますよね!そんな時は、Redis-cliコマンドで操作します。

スクリーンショット 2018-02-08 0.24.34.png

コマンドで

keys *

で全てのkeyを確認することができます。

試しに新しいkeyとvalueをgo-redis.goを実行していれてみます。

go run go-redis.go

実行後にもう一度、key確認をしてみると

スクリーンショット 2018-02-08 0.27.41.png

New_KEYがSETされています。

GETしてみると

スクリーンショット 2018-02-08 0.28.27.png

New_VALUEが取り出せています。

ちなみに、Key Value Storeなので値の更新は同じにKeyに対してSETして上書きするだけです。

当然、Keyを重複してRedisに登録することはできません。

疑問

ここで1つ疑問。1つのKEYに対して複数の要素を与えたい時ってどうすればいいのか。

Keyの重複登録ができないってことは・・・諦めるしかないんですかね。

ってことで調べてみました。

これはRedis自体の話になるんですが、格納するデータ構造によって登録するコマンドが違うみたいです。

ValueをList型にして、SETしてみても取り出した時にstring型の1文字1文字が数字に変換されてしまいます。

Redisとしては、1つのKeyにValueを詰めていく感じで登録してほしいみたいです。

1つのKeyにValueを詰め込んでいくコマンドはRPUSHです。

スクリーンショット 2018-02-08 0.29.02.png

このコマンドを実行すると、NewListKeyにValueが詰め込まれていきます。

取り出す時はGETではなく、LRANGEです。その際、Keyと取り出す範囲を指定するみたいです。

スクリーンショット 2018-02-08 0.29.51.png

第三引数が取り出し先頭のインデックス、第四引数が末尾のインデックスになります。-1を指定すると全ての値を取り出します。

これをGolangで書くと以下になります。

go-redis-list.go
package main

import (
  "github.com/garyburd/redigo/redis"
  "fmt"
  "os"
  _ "reflect"
)

func redisSet(key string, value string, c redis.Conn){
  c.Do("SET", key, value)
}

func redisSetList(key string, value []string, c redis.Conn){
  for _ , v := range value {
    fmt.Println(v)
    c.Do("RPUSH", key, v)
  }
}

func redisGet(key string, c redis.Conn) string{
  s, err := redis.String(c.Do("GET", key))
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  return s
}

func redisGetList(key string, c redis.Conn) []string{
  s, err := redis.Strings(c.Do("LRANGE", key, 0, -1))
  if err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  return s
}
func redisConnection() redis.Conn {
  const IP_PORT = "52.###.55.###:6379"

  //redisに接続
  c, err := redis.Dial("tcp", IP_PORT)
  if err != nil {
    panic(err)
  }
  return c
}

func main() {
  c := redisConnection()
  defer c.Close()

  var key = "New_KEY"
  var val = "Re_VALUE"
  redisSet(key, val, c)
  s := redisGet(key, c)
  fmt.Println(s)

  key = "List"
  var vallist = []string{"redis", "cash", "kvs"}
  redisSetList(key, vallist, c)
  sl := redisGetList(key, c)
  fmt.Println(sl)
  fmt.Println(sl[0])
  fmt.Println(sl[1])
  fmt.Println(sl[2])
}

実行結果は以下になります。

スクリーンショット 2018-02-08 0.30.14.png

これで1つのKeyに複数の要素を詰め込んで取り出すことができました!

以上で実践編はおしまいです。

終わりに

今回は最低限GETとSETができれば値の高速な呼び出しが可能となります。
今度はこれをアプリケーションに組み込んで、威力を確認してみたいと思います。

Go触っている方の少しでも参考になれば幸いです。

参考

Redisのデータ型

github.com/garyburd/redigo/tree/master/redis

49
35
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
49
35