始めに
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
ちゃんと起動出来ていると、
$ 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の扱いは大丈夫だと思います。
一応、以下サンプルコードです。
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コマンドで操作します。
コマンドで
keys *
で全てのkeyを確認することができます。
試しに新しいkeyとvalueをgo-redis.goを実行していれてみます。
go run go-redis.go
実行後にもう一度、key確認をしてみると
New_KEYがSETされています。
GETしてみると
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です。
このコマンドを実行すると、NewListKeyにValueが詰め込まれていきます。
取り出す時はGETではなく、LRANGEです。その際、Keyと取り出す範囲を指定するみたいです。
第三引数が取り出し先頭のインデックス、第四引数が末尾のインデックスになります。-1を指定すると全ての値を取り出します。
これをGolangで書くと以下になります。
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])
}
実行結果は以下になります。
これで1つのKeyに複数の要素を詰め込んで取り出すことができました!
以上で実践編はおしまいです。
終わりに
今回は最低限GETとSETができれば値の高速な呼び出しが可能となります。
今度はこれをアプリケーションに組み込んで、威力を確認してみたいと思います。
Go触っている方の少しでも参考になれば幸いです。