前回のRedisの冗長化では、Redisの標準機能を用いてRedisの冗長化を行う方法についてご紹介しました。
今回はRedisでマルチマスター構成のクラスタを組むための機能であるRedis Clusterについてご紹介します。
Redis Cluster
Redis Cluster は Redis 3.0 で実装されました。Redis Cluster はマルチマスター構成をとり、データは複数のRedisサーバに自動的に分散されます(シャーディング)。これにより書き込み負荷を分散させることができます。Redis Cluster は一部のノードが故障しても動作を継続し、ある程度の可用性を提供しますが、多数のノードが利用不可となった場合は動作を停止します。各マスターノードにはスレーブを持たせ、可用性を向上することができます。クラスタの最小構成は3マスターノードとなります。
Clusterが使用するポートは通常のポートに加え、クラスタの通信用に+10000したポート番号を使用します(6379の場合は16739)。
シャーディング
Redis Cluster はクラスタ全体で16384個(0~16383)のhash slotをもちます。各ノードにhash slotの一部分が割り当てられます。例えば以下のようになります。
- ノードA: 0~5460 の hash slot
- ノードB: 5461~10922 の hash slot
- ノードC: 10923~16383 の hash slot
クライアントがキーを登録するとき、キーごとにhash slotの値を計算し、対応するノードにデータが格納されます。キーからhash slotの値を求めるアルゴリズムは以下のようにシンプルなものとなります。
HASH_SLOT = CRC16(key) mod 16384
各ノードのhash slotは後から自由に移動することができるため、後からノードを追加したりノードを削除することが可能です。
Cluster の設定
本来は複数台のマシンで動作させますが、今回は1台のマシン上でポート番号を変えて6台の Cluster ノードを作成します。
名前 | ホスト名 | IPアドレス | ポート | クラスタポート |
---|---|---|---|---|
Node 1 | server1 | 192.168.1.1 | 7000 | 17000 |
Node 2 | server1 | 192.168.1.1 | 7001 | 17001 |
Node 3 | server1 | 192.168.1.1 | 7002 | 17002 |
Node 4 | server1 | 192.168.1.1 | 7003 | 17003 |
Node 5 | server1 | 192.168.1.1 | 7004 | 17004 |
Node 6 | server1 | 192.168.1.1 | 7005 | 17005 |
ノードごとに個別のディレクトリを作成し、既存の redis.conf をコピーして設定を行います。
# mkdir cluster-test # cd cluster-test/ # mkdir 7000 7001 7002 7003 7004 7005 # cp /etc/redis.conf 7000 # vi 7000/redis.conf # cp 7000/redis.conf 7001 # vi 7001/redis.conf ... # vi 7005/redis.conf
同サーバ上で動かすため、ファイル名が重複しないように適切に設定を行います。
port 7000 pidfile "/var/run/redis_7000.pid" logfile "/root/cluster-test/7000/redis.log" dbfilename "dump-7000.rdb" appendonly yes appendfilename "appendonly-7000.aof" cluster-enabled yes cluster-config-file nodes-7000.conf
各ノードを起動します。
# redis-server 7000/redis.conf # redis-server 7001/redis.conf # redis-server 7002/redis.conf # redis-server 7003/redis.conf # redis-server 7004/redis.conf # redis-server 7005/redis.conf
正常にプロセスが立ち上がり、 redis.log にエラーが出力されていないことを確認します。
# ps auxww|grep redis root 2939 0.1 0.1 153952 2772 ? Ssl 14:23 0:00 redis-server 0.0.0.0:7000 [cluster] root 2980 0.1 0.1 153952 2768 ? Ssl 14:24 0:00 redis-server 0.0.0.0:7001 [cluster] root 2985 0.2 0.1 153952 2768 ? Ssl 14:24 0:00 redis-server 0.0.0.0:7002 [cluster] root 2990 0.2 0.1 153952 2772 ? Ssl 14:24 0:00 redis-server 0.0.0.0:7003 [cluster] root 2995 0.3 0.1 153952 2776 ? Ssl 14:25 0:00 redis-server 0.0.0.0:7004 [cluster] root 3000 0.7 0.1 153952 2776 ? Ssl 14:25 0:00 redis-server 0.0.0.0:7005 [cluster]
/var/lib/redis 以下に各ノードの AOF およびクラスタ設定ファイルが作成されます。
# ls -l /var/lib/redis/ 合計 24 -rw-r--r--. 1 root root 0 6月 28 14:23 appendonly-7000.aof -rw-r--r--. 1 root root 0 6月 28 14:24 appendonly-7001.aof -rw-r--r--. 1 root root 0 6月 28 14:24 appendonly-7002.aof -rw-r--r--. 1 root root 0 6月 28 14:25 appendonly-7003.aof -rw-r--r--. 1 root root 0 6月 28 14:25 appendonly-7004.aof -rw-r--r--. 1 root root 0 6月 28 14:25 appendonly-7005.aof -rw-r--r--. 1 root root 114 6月 28 14:23 nodes-7000.conf -rw-r--r--. 1 root root 114 6月 28 14:24 nodes-7001.conf -rw-r--r--. 1 root root 114 6月 28 14:24 nodes-7002.conf -rw-r--r--. 1 root root 114 6月 28 14:25 nodes-7003.conf -rw-r--r--. 1 root root 114 6月 28 14:25 nodes-7004.conf -rw-r--r--. 1 root root 114 6月 28 14:25 nodes-7005.conf
次に、クラスタを作成します。 –cluster-replicas 1 はマスターごとに1つのレプリカ(スレーブ)を配置することを意味します。
なお、 Redis 3.0、4.0 の場合は redis-cli の代わりに redis-trib.rb という外部ツールを使用する必要があります。
# redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1
自動的にマスターとレプリカの割り当てが行われます。よければ yes を入力します。
>>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 127.0.0.1:7004 to 127.0.0.1:7000 Adding replica 127.0.0.1:7005 to 127.0.0.1:7001 Adding replica 127.0.0.1:7003 to 127.0.0.1:7002 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000 slots:[0-5460] (5461 slots) master M: a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001 slots:[5461-10922] (5462 slots) master M: a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002 slots:[10923-16383] (5461 slots) master S: 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003 replicates a5b82da0c32957954a3da1e16a3629083a8d5d8c S: 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004 replicates a18a55b7a4790c2bd1bd7fae057caa4144a03a52 S: 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005 replicates 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join ... >>> Performing Cluster Check (using node 127.0.0.1:7000) M: 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005 slots: (0 slots) slave replicates 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 S: 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004 slots: (0 slots) slave replicates a18a55b7a4790c2bd1bd7fae057caa4144a03a52 M: a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001 slots:[5461-10922] (5462 slots) master 1 additional replica(s) M: a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002 slots:[10923-16383] (5461 slots) master 1 additional replica(s) S: 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003 slots: (0 slots) slave replicates a5b82da0c32957954a3da1e16a3629083a8d5d8c [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
クラスタの構成が正常に完了すると [OK] All 16384 slots covered. というメッセージが出力されます。
なお、マスターとレプリカの組み合わせを自分で決定したい場合は、
最初にマスターのみでクラスタを構成した後、マスターを指定してレプリカを1つずつ追加していきます。
# redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 # redis-cli --cluster add-node 127.0.0.1:7003 127.0.0.1:7000 --cluster-slave --cluster-master-id 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 # redis-cli --cluster add-node 127.0.0.1:7004 127.0.0.1:7001 --cluster-slave --cluster-master-id a5b82da0c32957954a3da1e16a3629083a8d5d8c # redis-cli --cluster add-node 127.0.0.1:7005 127.0.0.1:7002 --cluster-slave --cluster-master-id a18a55b7a4790c2bd1bd7fae057caa4144a03a52
任意のノードに redis-cli で接続し、 cluster nodes コマンドを実行するとノードの一覧を取得することができます。これは nodes-7000.conf とほぼ同じ内容になります。
# redis-cli -p 7000 cluster nodes 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 slave 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 0 1561702297172 6 connected 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 myself,master - 0 1561702298000 1 connected 0-5460 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561702299186 5 connected a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 master - 0 1561702296161 2 connected 5461-10922 a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561702298000 3 connected 10923-16383 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561702298181 4 connected
Clusterの動作確認
redis-cli に -c を付けるとクラスタモードになります。これで動作を確認します。
# redis-cli -c -p 7000 127.0.0.1:7000> set foo 1 -> Redirected to slot [12182] located at 127.0.0.1:7002 OK 127.0.0.1:7002> get foo "1" 127.0.0.1:7002> set bar 2 -> Redirected to slot [5061] located at 127.0.0.1:7000 OK 127.0.0.1:7000> get bar "2" 127.0.0.1:7000> get foo -> Redirected to slot [12182] located at 127.0.0.1:7002 "1" 127.0.0.1:7002> get hoge -> Redirected to slot [1525] located at 127.0.0.1:7000 (nil) 127.0.0.1:7000> incr foo -> Redirected to slot [12182] located at 127.0.0.1:7002 (integer) 2 127.0.0.1:7002> get foo "2"
キーに応じてslotが変化し、対応するノードに自動的に接続を切り替えていることがわかります。
Clusterのクエリの制限
Clusterではキーごとに格納されるノードが異なるため、クライアント側でキーに対応するノードを知る必要があります(対応するノードはサーバから通知されます)。また、キーが複数のノードにまたがっている場合、複数のキーをまとめて取得する mget のようなコマンドは失敗します。
複数のキーを同じノードに割り当てたい場合、ハッシュタグ({ } で囲まれた文字列)を利用することができます。キーの一部に {…} という文字列を含めることで、 { } 内の文字列のみが hash slot の計算に使用されるようになります。以下の2つのキーは同一の hash slot となり、同じノードに格納されます。
{foo}hoge {foo}fuga
フェイルオーバー
7000番ポートのmasterに障害を発生させます。
# kill 2939 # ps auxww|grep redis root 2980 0.1 0.1 156512 3256 ? Ssl 14:24 0:07 redis-server 0.0.0.0:7001 [cluster] root 2985 0.1 0.1 158560 3284 ? Ssl 14:24 0:07 redis-server 0.0.0.0:7002 [cluster] root 2990 0.2 0.2 167264 4144 ? Ssl 14:24 0:07 redis-server 0.0.0.0:7003 [cluster] root 2995 0.2 0.1 160608 3372 ? Ssl 14:25 0:07 redis-server 0.0.0.0:7004 [cluster] root 3000 0.2 0.1 160608 3376 ? Ssl 14:25 0:07 redis-server 0.0.0.0:7005 [cluster]
cluster nodes の表示が fail となります。
# redis-cli -p 7001 cluster nodes 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 master,fail - 1561703162227 1561703160916 1 disconnected 0-5460 a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 myself,master - 0 1561703190000 2 connected 5461-10922 a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561703189000 3 connected 10923-16383 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561703190193 3 connected 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 slave 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 0 1561703189185 1 connected 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561703188000 4 connected
しばらくすると自動的に7000番ポートのmasterのslaveである7005番ポートのノードがmasterに昇格し、フェイルオーバーが完了します。
# redis-cli -p 7001 cluster nodes 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 master,fail - 1561703162227 1561703160916 1 disconnected a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 myself,master - 0 1561703238000 2 connected 5461-10922 a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561703240648 3 connected 10923-16383 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561703242665 3 connected 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 master - 0 1561703242000 8 connected 0-5460 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561703240000 4 connected
7000番ポートのRedisを再度起動すると、7005番ポートのmasterのslaveとして立ち上がり、再同期が行われます。
# redis-server 7000/redis.conf # redis-cli -p 7001 cluster nodes 70ed8f0f72ee70d2b55adfa722fcf1f9eb0c8111 127.0.0.1:7000@17000 slave 0a0dfeb8456c6bff470eddb24edae8743d6422ff 0 1561703557658 8 connected a5b82da0c32957954a3da1e16a3629083a8d5d8c 127.0.0.1:7001@17001 myself,master - 0 1561703558000 2 connected 5461-10922 a18a55b7a4790c2bd1bd7fae057caa4144a03a52 127.0.0.1:7002@17002 master - 0 1561703559675 3 connected 10923-16383 04a2ad5e2b0ea06bc9d90c3ab3c4214b2ac5cce9 127.0.0.1:7004@17004 slave a18a55b7a4790c2bd1bd7fae057caa4144a03a52 0 1561703556649 3 connected 0a0dfeb8456c6bff470eddb24edae8743d6422ff 127.0.0.1:7005@17005 master - 0 1561703558000 8 connected 0-5460 4d18eed5d6cdfc394f8cfa14a3655147393e3627 127.0.0.1:7003@17003 slave a5b82da0c32957954a3da1e16a3629083a8d5d8c 0 1561703558667 4 connected
おわりに
今回はRedisの標準機能の一つであるRedis Clusterについて紹介しました。Redis Clusterは必要なサーバ台数が多くなるものの、負荷分散と可用性を両立させることができます。
次回はPacemakerを用いたRedisの冗長化について紹介します。