Redis Clusterを作ってみる

Redis Clusterの作成方法を確認してみます。

環境

クラスター構成

1台のCentOS上に、プロセスを分けて各Redisサーバーを起動します。

Redisサーバー種類 Redis port Cluster Port
Redis Master 6379 16379
Redis Master 6380 16380
Redis Master 6381 16381
Redis Slave(Replica) 6382 16382
Redis Slave(Replica) 6383 16383
Redis Slave(Replica) 6384 16384

基本的なRedisの設定は実施済みとして、作業を進めます。

作成

公式ドキュメントを参考に作業を進めます。

Redis Cluster Tutorial

Cluster用パラメーター設定

公式ドキュメントとコンフィグ内の記載を参考に、必要パラメーターを設定します。

Redis Cluster configuration parameters

Redis configuration file example

こんな感じでしょうか。クラスターに参加する全Redisサーバーに設定します。

パラメーター名
cluster-enabled yes
cluster-config-file nodes-(redis port).conf
cluster-node-timeout 5000
cluster-replica-validity-factor 10
repl-ping-replica-period 10
cluster-migration-barrier 1
cluster-require-full-coverage yes
cluster-replica-no-failover no
cluster-allow-reads-when-down no
appendonly yes
appendfilename appendonly-(redis port).aof
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes

公式ドキュメントでは、Append Only Modeを有効とするように記載ありました。Append Only ModeとはAppend Only Fileを生成するModeとなっており、

The Append Only File, usually called simply AOF, is the main Redis persistence option. The way it works is extremely simple: every time a write operation that modifies the dataset in memory is performed, the operation gets logged. The log is produced exactly in the same format used by clients to communicate with Redis, so the AOF can be even piped via netcat to another instance, or easily parsed if needed. At restart Redis re-plays all the operations to reconstruct the dataset.

Redis persistence demystified

Relational Databaseにおけるアクティブログみたいなもの、という理解をしました。

Redisプロセスを起動すると、Clusterモードで起動されます。

$ ps -aef | grep redis | grep -v grep
redis      832     1  0 12:30 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6379 [cluster]
redis      838     1  0 12:30 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6384 [cluster]
redis      839     1  0 12:30 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6380 [cluster]
redis      840     1  0 12:30 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6382 [cluster]
redis      841     1  0 12:30 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6381 [cluster]
redis      842     1  0 12:30 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6383 [cluster]

Clusterの作成

パラメーターを設定してプロセスを起動しただけでは、RedisプロセスはClusterモードで起動しているのみで、実際にはCluster化されている訳ではありません。各RedisプロセスをCluster化するため、以下コマンドを実行します。

$ redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 --cluster-replicas 1
>>> 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:6383 to 127.0.0.1:6379
Adding replica 127.0.0.1:6384 to 127.0.0.1:6380
Adding replica 127.0.0.1:6382 to 127.0.0.1:6381
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 35180c311d8b46fd9b824878d0384de97131b181 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
M: 1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 127.0.0.1:6380
   slots:[5461-10922] (5462 slots) master
M: 3a97895f36a696893292160e73c31c35ac3f9ddb 127.0.0.1:6381
   slots:[10923-16383] (5461 slots) master
S: b3fa07636fc447b047f1ec18bb53d3b37697b807 127.0.0.1:6382
   replicates 35180c311d8b46fd9b824878d0384de97131b181
S: 147be2a171022d5bdba3ca3a122cf1d3a29d7ab7 127.0.0.1:6383
   replicates 1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb
S: e73b19a1f3e60eb74992baeb8c6e183904bd8573 127.0.0.1:6384
   replicates 3a97895f36a696893292160e73c31c35ac3f9ddb
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:6379)
M: 35180c311d8b46fd9b824878d0384de97131b181 127.0.0.1:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: e73b19a1f3e60eb74992baeb8c6e183904bd8573 127.0.0.1:6384
   slots: (0 slots) slave
   replicates 3a97895f36a696893292160e73c31c35ac3f9ddb
M: 1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 127.0.0.1:6380
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: b3fa07636fc447b047f1ec18bb53d3b37697b807 127.0.0.1:6382
   slots: (0 slots) slave
   replicates 35180c311d8b46fd9b824878d0384de97131b181
M: 3a97895f36a696893292160e73c31c35ac3f9ddb 127.0.0.1:6381
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 147be2a171022d5bdba3ca3a122cf1d3a29d7ab7 127.0.0.1:6383
   slots: (0 slots) slave
   replicates 1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

Creating the cluster

masterが3台、slave(replica)が3台で、Clusterが作成されています。

$ redis-cli cluster nodes
35180c311d8b46fd9b824878d0384de97131b181 127.0.0.1:6379@16379 myself,master - 0 1591278326000 1 connected 0-5460
e73b19a1f3e60eb74992baeb8c6e183904bd8573 127.0.0.1:6384@16384 slave 3a97895f36a696893292160e73c31c35ac3f9ddb 0 1591278326825 6 connected
1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 127.0.0.1:6380@16380 master - 0 1591278327333 2 connected 5461-10922
b3fa07636fc447b047f1ec18bb53d3b37697b807 127.0.0.1:6382@16382 slave 35180c311d8b46fd9b824878d0384de97131b181 0 1591278327838 4 connected
3a97895f36a696893292160e73c31c35ac3f9ddb 127.0.0.1:6381@16381 master - 0 1591278326000 3 connected 10923-16383
147be2a171022d5bdba3ca3a122cf1d3a29d7ab7 127.0.0.1:6383@16383 slave 1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 0 1591278326000 5 connected

CLUSTER NODES

Redis Clusterでは、登録されるKey毎に各master nodeへshardingされて格納されます。sharding先となるmasterは、keyごとに計算されるhash値により決定し、各master nodeにて格納することになるhash値が割り当てられています。上記のコマンド結果では、各master nodeのレコード末尾の 0-54605461-10922 が、割り当てられているhash値となります。

The key space is split into 16384 slots, effectively setting an upper limit for the cluster size of 16384 master nodes (however the suggested max size of nodes is in the order of ~ 1000 nodes).

Each master node in a cluster handles a subset of the 16384 hash slots.

The base algorithm used to map keys to hash slots is the following (read the next paragraph for the hash tag exception to this rule):

HASH_SLOT = CRC16(key) mod 16384

hash値を求めるより詳細なアルゴリズムは、公式にドキュメントに記載されています。

Keys distribution model

動作の確認

Cluster環境でのいくつかの動作を確認してみます。

リダイレクト

-c オプションをつけてredis-cliを起動すると、Cluster Modeでcliが起動して、コマンド実行時に適当なmaster nodeにリダイレクトしてくれるようなります。

$ redis-cli -c
127.0.0.1:6379> set key1 value1
-> Redirected to slot [9189] located at 127.0.0.1:6380
OK

A Redis client is free to send queries to every node in the cluster, including slave nodes. The node will analyze the query, and if it is acceptable (that is, only a single key is mentioned in the query, or the multiple keys mentioned are all to the same hash slot) it will lookup what node is responsible for the hash slot where the key or keys belong.

MOVED Redirection

-c オプションをつけない場合、リダイレクトされないため、接続しているnodeにkeyがない場合、処理に失敗します。

$ redis-cli
127.0.0.1:6379> get key1
(error) MOVED 9189 127.0.0.1:6380

keysは接続しているnodeのみを検索

nodeをまたいでkeyの検索はしてくれないようです。

$ redis-cli -c
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> get key1
-> Redirected to slot [9189] located at 127.0.0.1:6380
"value1"

格納するmaster nodeを固定する

hash tag というものを利用できるそうです。

There is an exception for the computation of the hash slot that is used in order to implement hash tags. Hash tags are a way to ensure that multiple keys are allocated in the same hash slot. This is used in order to implement multi-key operations in Redis Cluster.

In order to implement hash tags, the hash slot for a key is computed in a slightly different way in certain conditions. If the key contains a "{...}" pattern only the substring between { and } is hashed in order to obtain the hash slot.

Keys hash tags

こんな感じで、波括弧で囲んだ文字列にてhash値を取得してくれるため、同一のmasterにkeyが格納されることになります。

$ redis-cli -c
127.0.0.1:6379> set {key1}.one 1
-> Redirected to slot [9189] located at 127.0.0.1:6380
OK
127.0.0.1:6380> set {key1}.two 2
OK
127.0.0.1:6380> keys {key1}.*
1) "{key1}.one"
2) "{key1}.two"

msetコマンド利用時も、hash tagを利用することになります。

$ redis-cli -c
127.0.0.1:6379> mset {key2}.one 1 {key2}.two 2
OK
127.0.0.1:6379> mset key3.one 1 key3.two 2
(error) CROSSSLOT Keys in request don't hash to the same slot

Multiple keys operations

cluster環境ではdatabaseが0のみとなる

Redis Cluster does not support multiple databases like the stand alone version of Redis. There is just database 0 and the SELECT command is not allowed.

とのこと。

$ redis-cli -c
127.0.0.1:6379> select 1
(error) ERR SELECT is not allowed in cluster mode

failoverの動作確認

failover時の動作を確認します。

プロセスの起動状況を確認。

$ ps -aef | grep redis | grep -v grep
redis      827     1  0 22:46 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6381 [cluster]
redis      829     1  0 22:46 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6380 [cluster]
redis      832     1  0 22:46 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6382 [cluster]
redis      834     1  0 22:46 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6384 [cluster]
redis      836     1  0 22:46 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6383 [cluster]
redis     2239     1  0 22:49 ?        00:00:00 /usr/local/bin/redis-server 127.0.0.1:6379 [cluster]

6379ポート起動のredisを停止します。

$ sudo systemctl stop redis-6379

該当のRedis Masterがfailとなり、slave(Replica)であったものがMasterに昇格しています。

$ redis-cli -p 6380 cluster nodes
35180c311d8b46fd9b824878d0384de97131b181 127.0.0.1:6379@16379 master,fail - 1591311034818 1591311032567 1 disconnected
b3fa07636fc447b047f1ec18bb53d3b37697b807 127.0.0.1:6382@16382 master - 0 1591311074142 7 connected 0-5460
3a97895f36a696893292160e73c31c35ac3f9ddb 127.0.0.1:6381@16381 master - 0 1591311073632 3 connected 10923-16383
1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 127.0.0.1:6380@16380 myself,master - 0 1591311072000 2 connected 5461-10922
e73b19a1f3e60eb74992baeb8c6e183904bd8573 127.0.0.1:6384@16384 slave 3a97895f36a696893292160e73c31c35ac3f9ddb 0 1591311073000 6 connected
147be2a171022d5bdba3ca3a122cf1d3a29d7ab7 127.0.0.1:6383@16383 slave 1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 0 1591311073632 5 connected

停止したものを起動。

$ sudo systemctl start redis-6379

slave(Replica)として起動してきています。

$ redis-cli -p 6380 cluster nodes
35180c311d8b46fd9b824878d0384de97131b181 127.0.0.1:6379@16379 slave b3fa07636fc447b047f1ec18bb53d3b37697b807 0 1591311147097 7 connected
b3fa07636fc447b047f1ec18bb53d3b37697b807 127.0.0.1:6382@16382 master - 0 1591311146079 7 connected 0-5460
3a97895f36a696893292160e73c31c35ac3f9ddb 127.0.0.1:6381@16381 master - 0 1591311147605 3 connected 10923-16383
1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 127.0.0.1:6380@16380 myself,master - 0 1591311147000 2 connected 5461-10922
e73b19a1f3e60eb74992baeb8c6e183904bd8573 127.0.0.1:6384@16384 slave 3a97895f36a696893292160e73c31c35ac3f9ddb 0 1591311148113 6 connected
147be2a171022d5bdba3ca3a122cf1d3a29d7ab7 127.0.0.1:6383@16383 slave 1e130c2c295bdb9cd7c03c86a5d7e2bc2c3925cb 0 1591311147000 5 connected