Redisをクラスタ構成で動かす
構築メモにて。
環境
- Ubuntu 14.04
実験
redis-cli
でいろいろ実験してみる。なお、redis-cli
に、-c
オプションをつけないと、値の設定や取得でエラーになる。(-c
はクラスタモード。)
-c
をつけずに値の設定や取得を行うと、以下のようなエラーになる。
127.0.0.1:7000> set key1 100
(error) MOVED 9189 127.0.0.1:7001
127.0.0.1:7000> get key1
(error) MOVED 9189 127.0.0.1:7001
GET/SET
key1
に値100
を設定してみた。
key1
は、ハッシュスロット9189に保存されたようだ。Redisが自動的に振り分けて7001
のノードにリダイレクトしている。
127.0.0.1:7000> set key1 100
-> Redirected to slot [9189] located at 127.0.0.1:7001
OK
127.0.0.1:7001> get key1
"100"
MGET
今度は、MGET
で複数の値を取得してみる。
まずは新たに値key2:200
を追加する。すると、今度は7000
のノードに保存した。
127.0.0.1:7001> set key2 200
-> Redirected to slot [4998] located at 127.0.0.1:7000
OK
127.0.0.1:7000> get key2
"200"
この時点で、key1
は7001
のノードに、key2
のノードは7000
のノードに保存されている。この状態で、MGET
を実行して正常に取得できるか?
実行してみると、スロットを跨いで取得することは出来ない。
127.0.0.1:7001> mget key1 key2
(error) CROSSSLOT Keys in request don't hash to the same slot
では、どのようにすればMGETすることが出来るようになるか?ここで、ハッシュタグ
の出番。ハッシュタグ
とは、キーに{foo}
のようにブラケットで囲んだ文字列を付与することにより、同じハッシュスロットに割り当てる機能である。
では実際にやってみるとどうなるか?以下は、{tag}
というハッシュタグを、key1
/key2
に付与してMGET
してみる。
正常に動作しているようである。
127.0.0.1:7001> set {tag}key1 1000
OK
127.0.0.1:7001> get {tag}key1
"1000"
127.0.0.1:7001> set {tag}key2 2000
OK
127.0.0.1:7001> get {tag}key2
"2000"
127.0.0.1:7001> mget {tag}key1 {tag}key2
1) "1000"
2) "2000"
では、ハッシュタグ{tag}
を付与した値が保存されたノードは7001
であるが、7000
のノードで、{tag}
を付与した値をSETするとどうなるか?
7001
のノードにリダイレクトした後、SETしてくれている。
127.0.0.1:7000> set {tag}key3 3000
-> Redirected to slot [8338] located at 127.0.0.1:7001
OK
このように、ハッシュタグを付与した値は、同じノードに対してSETしてくれることがわかった。
MGET
などのように、複数のキーに対して何かを行うようなコマンドを使う場合は、予めハッシュタグを考慮して設計する必要がありそうだ。
Pub/Sub
同じノードでPub/Sub
まずは簡単に、同一ノードに接続したPublisherとSubscriberで正常に動作するか確認してみる。以下のコマンドを2つターミナルを立ち上げ実行する。
- Subscriber
127.0.0.1:7000> SUBSCRIBE 'channel:7000'
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel:7000"
3) (integer) 1
- Publisher
127.0.0.1:7000> PUBLISH 'channel:7000' 'Hello from 7000'
(integer) 1
結果、Subscriberに正常に通知された。
127.0.0.1:7000> SUBSCRIBE 'channel:7000'
… (snip) …
1) "message"
2) "channel:7000"
3) "Hello from 7000"
異なるノードでPub/Sub
今度は、Publisherを異なるノードに接続し、Publishしてみる。
127.0.0.1:7001> PUBLISH 'channel:7000' 'Hello from 7001'
(integer) 0
127.0.0.1:7001>
結果、Subscriberに正常に通知された。
127.0.0.1:7000> SUBSCRIBE 'channel:7000'
… (snip) …
1) "message"
2) "channel:7000"
3) "Hello from 7001"
PubをSlaveに接続してPub/Sub
今度は、Publisherをスレーブに接続してPublishしてみる。
127.0.0.1:7004> PUBLISH 'channel:7000' 'Hello from 7004'
(integer) 0
結果、Subscriberに正常に通知された。
127.0.0.1:7000> SUBSCRIBE 'channel:7000'
… (snip) …
1) "message"
2) "channel:7000"
3) "Hello from 7004"
アクティブなチャネル一覧の取得
PUBSUB CHANNELS [pattern]
で、アクティブなチャネル一覧を取得できるが、クラスタ環境で取得可能か確かめる。
Subscriberは、7000
でチャネルchannel:7000
をSubscribeしている状態である。
127.0.0.1:7000> SUBSCRIBE 'channel:7000'
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel:7000"
3) (integer) 1
まずは同じノードから。正常に取得できた。
127.0.0.1:7000> PUBSUB CHANNELS 'channel:7000'
1) "channel:7000"
次に、異なるノード7001
から。取得できない。
どうやら、PUBSUB CHANNELS
は、PubとSubが異なるノードの場合、期待通りに動作しないようだ。
127.0.0.1:7001> PUBSUB CHANNELS 'channel:7000'
(empty list or set)
ちなみに、ハッシュタグをつけても無駄である。
アクティブなチャネル数の取得
PUBSUB NUMSUB [channel]
で、アクティブなチャネル数を取得することが出来るが、クラスタ環境で正常に動作するか試す。PUBSUB CHANNELS
の場合と同様、7000
のノードでSUBしている状態で試した。
まずは同じノードから。正常に取得できた。
127.0.0.1:7000> PUBSUB NUMSUB 'channel:7000'
1) "channel:7000"
2) (integer) 1
次に、異なるノードから。取得できない。
127.0.0.1:7001> PUBSUB NUMSUB 'channel:7000'
1) "channel:7000"
2) (integer) 0
ちなみに、ハッシュタグをつけても無駄である。