peropero

フリーランスのインフラエンジニア

RedisClusterをちょっとだけ試してみる。

この記事はMikeTOKYO Advent Calendar 2013の6日目です。


こんばんわ、osawagiboyです。

まさかのこの日に初投稿です。


さて、まさかのクリスマス・イブの日とリリース前のこの状況でやろうぜと
誘っていただいたチャンタケ氏恨みます。感謝します。

タイトルどおり、今流行りのRedisのクラスタ構成を組めるRedis-Clusterを使えるか試してみました。

ちなみにまだunstableです。

というのもsocket.ioでRedisを共有ストアとして利用した場合、チャンタケ氏が公開しているこちらにも書いている通り
構成やRedisサーバのスケールが少し複雑かつ面倒というのを解決できへんかなーと。

Redis clusterの詳細については こちらを参照してください。

Cassandraなどと同様、クラスタ間をGossipでやりとりするようですね。

とりあえず試します。
むっちゃ長くなってしまった・・・。



環境構築



Vagrantを使ってVirtualBox上にクラスタを構成します。

RedisClusterインストール
利用するポートはmasterでポート:(6301,6302,6303)を構築します。

[vagrant@localhost src]$ sudo git clone https://github.com/antirez/redis
[vagrant@localhost redis]$ sudo make MALLOC=jemalloc
[vagrant@localhost redis]$ sudo make install

mallocのライブラリをjemallocにした以外は基本デフォルトでさくっと入れちゃいます。
詳細は公式のgithubをみてください。



redis.conf設定
設定ファイルは基本デフォルトで各ポート用に変更しています。

現状Clusterの設定は3つあります。

cluster-enabled yes
=> クラスタモード
cluster-config-file nodes-6301.conf
=> 自クラスタ情報の管理ファイル名
cluster-node-timeout 5
=> 各ノードのタイムアウト


今回使う設定。※Master用

daemonize no
pidfile /var/run/redis.pid
port 6301
timeout 0

tcp-keepalive 0
loglevel notice
logfile "./redis-6301.log"

databases 16

#save 900 1
#save 300 10
#save 60 10000

stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb

dir ./

slave-serve-stale-data yes
slave-read-only yes
repl-disable-tcp-nodelay no
slave-priority 100

appendonly no
appendfsync everysec
no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128

notify-keyspace-events ""

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

list-max-ziplist-entries 512
list-max-ziplist-value 64

set-max-intset-entries 512

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

activerehashing yes

client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

hz 10
aof-rewrite-incremental-fsync yes

# ----cluster----
# #
cluster-enabled <span style="color: #ff2600">yes</span>
cluster-config-file /etc/redis/nodes-6301.conf


ClusterModeでRedis起動
ではMasterの6301,6302,6303を起動!
vm.overcommit_memory = 1設定しておかないとwarning出ます。

[vagrant@localhost redis]$ sudo /usr/local/bin/redis-server /etc/redis/redis-6301.conf
[12180] 24 Dec 03:04:17.249 * Max number of open files set to 10032
[12180] 24 Dec 03:04:17.250 * Node configuration loaded, I'm bf7b266d12345fd68d7f7c9233bcd71d473f0a41
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 2.9.11 (e7893842/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in cluster mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6301
 |    `-._   `._    /     _.-'    |     PID: 12180
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

[12180] 24 Dec 03:04:17.250 # Server started, Redis version 2.9.11
[12180] 24 Dec 03:04:17.251 * The server is now ready to accept connections on port 6301

起動するとnodes-6301.confファイルのようにCluster情報を管理します。
まだクラスタを組んでいないので、自分しかいませんが。

[vagrant@localhost redis]$ sudo cat nodes-6301.conf
ec77ab685cc6ae9a8ebbf59de0da12d8537801c4 :0 myself,master - 0 0 0 connected
[vagrant@localhost redis]$ sudo cat nodes-6302.conf
b1eeb99149cc25514791474e445098d435b4215c :0 myself,master - 0 0 0 connected
[vagrant@localhost redis]$ sudo cat nodes-6303.conf
65663be105a627ed06163c4e1ef95bbf997ce937 :0 myself,master - 0 0 0 connected

また、redis-cliでも確認できます。

[vagrant@localhost redis]$ sudo /usr/local/bin/redis-cli -p 6301 cluster nodes
ec77ab685cc6ae9a8ebbf59de0da12d8537801c4 :0 myself,master - 0 0 0 connected
[vagrant@localhost redis]$ sudo /usr/local/bin/redis-cli -p 6302 cluster nodes
b1eeb99149cc25514791474e445098d435b4215c :0 myself,master - 0 0 0 connected
[vagrant@localhost redis]$ sudo /usr/local/bin/redis-cli -p 6303 cluster nodes
65663be105a627ed06163c4e1ef95bbf997ce937 :0 myself,master - 0 0 0 connected

ちなみにnodes-{port}.confファイルを削除してRedisを再起動すると新規クラスタとして起動しました。
Cassandraとかは一度起動すればRing情報をデータに持っていたけど、RedisClusterもディスク書き出ししていれば、保存されるのかな?
今度試してみます。


クラスタを構成
では本命のクラスタを構成します!
RedisClusterの管理ツールとしてredis-trib.rbが用意されていますので、こちらで追加していきたいと思います。

[vagrant@localhost redis]$ sudo src/redis-trib.rb
src/redis-trib.rb:24:in `require': no such file to load -- rubygems (LoadError)
        from src/redis-trib.rb:24

あれ!?と思ったらredisのrubyライブラリが必要なようです。


ライブラリいれて気を取り直し・・・めんどいのでrootでいきます。

[root@localhost redis]# src/redis-trib.rb
Usage: redis-trib <command> <options> <arguments ...>

  create     host1:port1 ... hostN:portN
  check      host:port
  fix        host:port
  reshard    host:port
  addnode    new_host:new_port existing_host:existing_port
  help       (show this help)

無事使えるようなのでクラスタを構成していきます。

[root@localhost redis]# ./src/redis-trib.rb create 127.0.0.1:6301 127.0.0.1:6302
>>> Creating cluster
Connecting to node 127.0.0.1:6301: OK
Connecting to node 127.0.0.1:6302: OK
*** ERROR: Invalid configuration for cluster creation.
*** Redis Cluster requires at least 3 master nodes.
*** This is not possible with 2 nodes and 0 replicas per node.
*** At least 3 nodes are required.

3台以上ないとダメらしい。


もっかい

[root@localhost redis]# ./src/redis-trib.rb create 127.0.0.1:6301 127.0.0.1:6302 127.0.0.1:6303
>>> Creating cluster
Connecting to node 127.0.0.1:6301: OK
Connecting to node 127.0.0.1:6302: OK
Connecting to node 127.0.0.1:6303: OK
>>> Performing hash slots allocation on 3 nodes...
Using 3 masters:
127.0.0.1:6301
127.0.0.1:6302
127.0.0.1:6303
M: ec77ab685cc6ae9a8ebbf59de0da12d8537801c4 127.0.0.1:6301
   slots:0-5460 (5461 slots) master
M: b1eeb99149cc25514791474e445098d435b4215c 127.0.0.1:6302
   slots:5461-10921 (5461 slots) master
M: 65663be105a627ed06163c4e1ef95bbf997ce937 127.0.0.1:6303
   slots:10922-16383 (5462 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join..
>>> Performing Cluster Check (using node 127.0.0.1:6301)
M: ec77ab685cc6ae9a8ebbf59de0da12d8537801c4 127.0.0.1:6301
   slots:0-5460 (5461 slots) master
M: b1eeb99149cc25514791474e445098d435b4215c 127.0.0.1:6302
   slots:5461-10921 (5461 slots) master
M: 65663be105a627ed06163c4e1ef95bbf997ce937 127.0.0.1:6303
   slots:10922-16383 (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

無事できた?!てことで確認していきます。


redis-cliで接続する場合-cをつける必要があります。

[root@localhost redis]# redis-cli -c -p 6301
127.0.0.1:6301> cluster nodes
b1eeb99149cc25514791474e445098d435b4215c 127.0.0.1:6302 master - 0 1387823588047 0 connected 5461-10921
ec77ab685cc6ae9a8ebbf59de0da12d8537801c4 :0 myself,master - 0 0 0 connected 0-5460
65663be105a627ed06163c4e1ef95bbf997ce937 127.0.0.1:6303 master - 0 1387823587037 0 connected 10922-16383

いけてるっぽい!

では続いて現状のコマンドが利用可能か確認していきます。

コマンド検証



SET/GET

Set

[root@localhost redis]# redis-cli -c -p 6301
127.0.0.1:6301> set key1 val1
-> Redirected to slot [9189] located at 127.0.0.1:6302
OK
127.0.0.1:6302>

接続先は6301でしたが、Set時にRedirectされるようです。
Redirect後は6302に接続されてますね。

Get

[root@localhost redis]# redis-cli -c -p 6303
127.0.0.1:6303> get key1
-> Redirected to slot [9189] located at 127.0.0.1:6302
"val1"
127.0.0.1:6302>

Setと同じですね。
実際の動作としてはクライアント(get)=>6303(6302にデータがあるという情報を返す)=>クライアント(get)=>6302といった感じのようです。
ただ無駄なリダイレクトが挟むので実際には、各クラスタのhash slotの情報を共有して対象のノードにデータをとりにいく感じになるのかな?
http://redis.io/presentation/Redis_Cluster.pdf

multi keysは公式に記載どおり使えませんでした、

127.0.0.1:6302> set key2 val2
-> Redirected to slot [4998] located at 127.0.0.1:6301
OK
127.0.0.1:6301> mget key1 key2
(error) ERR Multi keys request invalid in cluster

ちなみにhashは使えましたが、データ分散されませんでした。


Pub/Sub

では本命のPub/Subです。
6301ポートでsubscribe、6302からpublishしてみます。

pub(6302)

127.0.0.1:6302> PUBLISH room1  hogehoge
(integer) 0

sub(6301)

[root@localhost ~]# redis-cli -c -p 6301
127.0.0.1:6301> SUBSCRIBE room1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "room1"
3) (integer) 1
1) "message"
2) "room1"
3) "hogehoge"

キター。まあいけるでしょうが・・・。


その他
その他のコマンドですが、全部試していないのでまた時間あるとき試してみます。
ただmonitorコマンドはClusterをサポートしていないみたい。

[root@localhost ~]# redis-cli -c -p 6302
127.0.0.1:6302> set key3 val3
-> Redirected to slot [935] located at 127.0.0.1:6301
OK
127.0.0.1:6301> set key4 val4
-> Redirected to slot [13120] located at 127.0.0.1:6303
OK
127.0.0.1:6303>

monitor

[root@localhost ~]# redis-cli -c -p 6301 monitor
OK
1387824965.427047 [0 127.0.0.1:45907] "set" "key3" "val3"

ポート6301へのSetしかモニタリングされてない。

総評


今回、RedisClusterの動作を確認しましたが、サポートされていないコマンドが少しあったぐらいで普通にPub/Subを利用するぐらいであればいけそうです。
ただ、メインである耐障害性の検証は確認していないのでまた時間があるときにできたら書きます。てかそこやれよって感じですが・・・。

後、今回詳細には書きませんでしたが(書けよ)、redis-trib.rbでSlotの再配置コマンドを発行している最中にSetを1000/secぐらいで試していたらnilがいくつか返っておりクラスタのSlot内から外れていました。
実際に対象のポートにredis-cliの-cなしで接続すれば見れました。
というようなまだ不安定な箇所があるので、今は遊ぶぐらいですね。まだunstableやから当然か。



最後に!
すげー雑な感じになっちゃいましてすいません。
今回のRedisClusterのような分散データベースは検証してる分にはすごい楽しいのですが、実際運用するとなるとコストが高いのとConsistencyの部分が問題となるので本当に要件がマッチした時だけ使うのをおすすめします。
Redisとか保管すべきデータとか乗せちゃほんとダメ。後々きつい。
Cassandraとか・・・Cassandraとか・・・。




すごく長くなってしまいましたが、読んでいただいてありがとうございました!
また、誘ってくれたチャンタケ氏に感謝します。
明日は誰やろなー??