MacOSX で redis3.0.0 の cluster を試してみた
install redis3.0.0 to MacOSX
brew ではまだ 3.0.0 の用意がない模様
cd ~/Downloads curl -O http://download.redis.io/releases/redis-3.0.0.tar.gz tar zxvf redis-3.0.0.tar.gz cd redis-3.0.0 make test make make install
もし brew で管理されている redis 2.8.19 に戻したい場合は rm -fr /usr/local/bin/redis-* してから brew uninstall redis
からの brew install redis
すればいける気がします(あんまりよくわかっていない)
Cluster
こちらを参考にして準備します
http://toufuegg.hatenablog.com/entry/2015/04/04/170309
% mkdir ~/cluster-test && cd $_ % mkdir 700{0,1,2,3,4,5} % cat <<EOS > redis.conf port 7000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes EOS % for i in {0..5}; do cp -av redis.conf "700$i/"; sed -i -e "s/port 7000/port 700$i/g" "700$i/redis.conf"; done
作成したディクレトリに移動してから redis-server redis.conf を実行する。 たぶんバックグラウンドで動かすよりもフォアグランドで動かしたほうがログ見やすい気がします。
% cd 7000 && redis-server redis.conf % cd 7001 && redis-server redis.conf % cd 7002 && redis-server redis.conf % cd 7003 && redis-server redis.conf % cd 7004 && redis-server redis.conf % cd 7005 && redis-server redis.conf
redis-3.0.0 に同梱されている ruby スクリプトを使用します。 gem install redis しないと動かないので rbenv などで各自 ruby のセットアップをお願いします。
% cd ~/Downloads/redis-3.0.0/src % ./redis-trib.rb create --replicas 0 \ 127.0.0.1:7000 \ 127.0.0.1:7001 \ 127.0.0.1:7002 \ 127.0.0.1:7003 >>> Creating cluster Connecting to node 127.0.0.1:7000: OK Connecting to node 127.0.0.1:7001: OK Connecting to node 127.0.0.1:7002: OK Connecting to node 127.0.0.1:7003: OK >>> Performing hash slots allocation on 4 nodes... Using 4 masters: 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 M: 05197142d6b02fdd3f7c68214082f859892facf0 127.0.0.1:7000 slots:0-4095 (4096 slots) master M: c4f6d0d61b3542749d6a39afb26979bd8cf88744 127.0.0.1:7001 slots:4096-8191 (4096 slots) master M: 23de6cb0a1e609bac71e4f4daa32ea4923cd2d22 127.0.0.1:7002 slots:8192-12287 (4096 slots) master M: e16004ece64c55bd43562f11c4a6f1a1ecb866fb 127.0.0.1:7003 slots:12288-16383 (4096 slots) master Can I set the above configuration? (type 'yes' to accept): yes とタイプしてから Enter
以下で確認します。
% redis-cli -p 7000 cluster nodes 23de6cb0a1e609bac71e4f4daa32ea4923cd2d22 127.0.0.1:7002 master - 0 1428304456836 3 connected 8192-12287 e16004ece64c55bd43562f11c4a6f1a1ecb866fb 127.0.0.1:7003 master - 0 1428304455802 4 connected 12288-16383 c4f6d0d61b3542749d6a39afb26979bd8cf88744 127.0.0.1:7001 master - 0 1428304455285 2 connected 4096-8191 05197142d6b02fdd3f7c68214082f859892facf0 127.0.0.1:7000 myself,master - 0 0 1 connected 0-4095
この後 re-sharding などの動作確認を試したい方はこちらの記事がいい感じです。是非実際に動作検証してみてください。 http://toufuegg.hatenablog.com/entry/2015/04/04/170309
本題
redis-server がクラスタリングしている場合、クライアントはどうやって値を取得しているのか、というのがこの記事の趣旨です。
値を SET すると 7000 -> 7002 へダイレクトされる
% redis-cli -c -p 7000 127.0.0.1:7000> set foo bar -> Redirected to slot [12182] located at 127.0.0.1:7002 OK 127.0.0.1:7002> get foo "bar" 127.0.0.1:7002> Quit
再度 7000 port へ接続して GET してみる
% redis-cli -c -p 7000 127.0.0.1:7000> get foo -> Redirected to slot [12182] located at 127.0.0.1:7002 "bar" 127.0.0.1:7002> Quit
接続先が切り替わっている事が確認できます。
低能なクライアントと賢いクライアント
redis-server がクラスタリングしている場合、クライアント側では2つの挙動が存在します。 よく見ると先ほどの redis-cli コマンドは -c をオプションにつけています。
% redis-cli -h (中略) -c Enable cluster mode (follow -ASK and -MOVED redirections).
Enable cluster mode は ASK redirections と Moved redirections という挙動があるようです。
MOVED redirections は先ほどの挙動です。7000 port の redis-server プロセスに SET, GET を試みているのですがその都度 7000 port の redis-server に「いや、その Key はこっちじゃなくてあっちに行かないとだめよ、だめ(ry」と言われてしまっています。
つまり2回通信が発生しています。これが低能なクライアントの挙動です(実はあんまりわかっていない)
もうひとつ ASK redirection という方式があり、こちらは賢い挙動をします。
賢いクライアントは初回のリクエスト時に各 redis-server へのコネクション、ハッシュスロットとノードの対応表を保存しておき、最初から目当てのノードに対してリクエストします(たぶん) もし対応表に変更があれば、また初回リクエスト時と同じように各種情報をサーバーから返してもらい、次回から目当てのノードに対して直接リクエストします。
http://redis.shibu.jp/admin/cluster/#id3
パイプライニングやマルチコマンドで複数のノードをまたぐ場合の挙動
とりあえず mget はだめだった
% redis-cli -c -p 7000 127.0.0.1:7000> get foo -> Redirected to slot [12182] located at 127.0.0.1:7002 "bar" 127.0.0.1:7002> set key2 val2 -> Redirected to slot [4998] located at 127.0.0.1:7001 OK 127.0.0.1:7001> set key1 val1 -> Redirected to slot [9189] located at 127.0.0.1:7002 OK 127.0.0.1:7002> mget key1 key2 (error) CROSSSLOT Keys in request don't hash to the same slot
パイプライニング は期待した結果にならない
% (printf "get key1\r\nget key2\r\nget key1\r\n"; sleep 1) | nc localhost 7000 -MOVED 9189 127.0.0.1:7002 -MOVED 4998 127.0.0.1:7001 -MOVED 9189 127.0.0.1:7002
まとめ
既存のサービスが mget を多用している場合はクラスタリングはちょっと厳しいかも。