【KVS】CentOS 6 に Redis-Cluster を構築する

CentOS 6.8 に Redis-3.2.5 をインストールし, Redis-Cluster を構築するメモです。
(2018-10-30: 2018-10-17 にリリースされた Redis 5.0.0 ではクラスターの構築方法が変更となったため追記しました)

CentOS 6 に Redis インストール

最新安定版の Redis 3.2.5 をソースからインストールする。

$ wget download.redis.ioreleasesredis-3.2.5.tar.gz
$ redis-3.2.5 tar xzvf redis-3.2.5.tar.gz
$ cd redis-3.2.5
$ make

make test 実行のために tcl (8.5以上)をインストール。また `[err]: Test replication partial resync: ok psync` エラー[1] の対策のため, taskset コマンドを使う。

$ sudo yum install tcl 
$ taskset -c 0 make test
$ sudo make install
$ redis-server --version
$ redis-cli -p 6379 ping
PONG

インストールに成功したら, install_server.sh で設定ファイルの 生成・配置・起動スクリプト(chkconfig)などの設定などを行う。

$ cd utils
$ sudo ./install_server.sh
Welcome to the redis service installer
This script will help you easily set up a running redis server

Please select the redis port for this instance: [6379] 6379
Please select the redis config file name [/etc/redis/6379.conf]
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379]
Selected default - /var/lib/redis/6379
Please select the redis executable path [] /usr/local/bin/redis-server
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!

Redis のメモリ制限は maxmemory ディレクティブで設定でき, CONFIG GET コマンドで確認できる。0 の場合は無制限 (=システムの上限) となる。

127.0.0.1:6379> CONFIG GET maxmemory
1) "maxmemory"
2) "0"

また, メモリ枯渇時の振る舞いはポリシーによって変わり, maxmemory-policy ディレクティブで設定でき default は書き込みコマンド系でエラーを返す noeviction となっている。

Redis-Cluster の構築

master3台の構成で Cluster を構築する。 負荷分散できることはもちろん, Node間で互いに監視するので監視専用サーバーが要らないのも利点。
上記の手順で各ホストに Redis をインストールしてある状態とする。Cluster として動かすために redis.conf を変更する。

$ sudo vim /etc/redis/redis_6379.conf
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
appendonly yes

また, password認証が必要な場合は requirepass のように追加する。

変更した redis.conf を各ホストに配布し再起動する。

$ for host in 192.168.10.1 192.168.10.2 192.168.10.3; do scp redis_6379.conf root@$host:/etc/redis/; ssh root@$host "sudo /etc/init.d/redis_6379 restart"; done

Redis 5.0.0 より以前の場合は, Cluster を構築する utils/redis-trib.rb の実行に必要なソフトウェアをインストールする。redis-trib.rb が内部で redis-client を使っているらしく最新の 3.2.2 が原因で動かず 3.2.1 に落としたら動いた。(Redis 5.0.0 以降の場合は後述)

# Ruby 1.8.7.374-4.el6_6 & Rubygems 1.3.7-5.el6 
$ sudo yum install ruby
$ sudo yum install rubygems
$ sudo gem install redis -v 3.2.1

$ ./redis-trib.rb create 192.168.10.1:6379 192.168.10.2:6379 192.168.10.3:6379

Cluster の構成は CLUSTER NODES コマンドで確認できる。

$ redis-cli -p 6379 -c
127.0.0.1:6379> cluster nodes
5018bdc02898b53c752e3b7df91e46a8aad6d4af 192.168.10.1:6379 master - 0 1481017459922 3 connected 0-5460
57ba77cbfa6b7fa831946a60e77c89e76aa88771 192.168.10.2:6379 myself,master - 0 0 1 connected 10923-16383
da9757c83d88a6d84f3e68d3e4cfb2ea0e7531d4 192.168.10.3:6379 master - 0 1481017461927 2 connected 5461-10922

`redis-cli -c` は `Enable cluster mode (follow -ASK and -MOVED redirections).` のはずなんだけど, KEYS は redirect してくれない場合があって全ノード見にいったりしている。

for i in 1 2 3; do redis-cli -h 192.168.10.$i -p 6379 -c KEYS "*"; done

Redis-Cluster の構築 (Redis 5.0.0)

Redis 5.0.0 で utils/redis-trib.rb の機能が redis-cli コマンドに統合された。従って, Redis 5.0.0 以降では redis-cli で Redis-Cluster を構築する。

 # Redis 5.0.0
$ redis-cli --cluster create \
>   127.0.0.1:6377 \
>   127.0.0.1:6378 \
>   127.0.0.1:6379
>>> Performing hash slots allocation on 3 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
M: 80fb9f089d891a581b73172f083326b179bf9a79 127.0.0.1:6377
   slots:[0-5460] (5461 slots) master
M: 2ceb444b77d974515aed477b4ae941e361995ae2 127.0.0.1:6378
   slots:[5461-10922] (5462 slots) master
M: 04cdccf3cf41e2e590d9883634874c2fc8d94796 127.0.0.1:6379
   slots:[10923-16383] (5461 slots) master
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:6377)
M: 80fb9f089d891a581b73172f083326b179bf9a79 127.0.0.1:6377
   slots:[0-5460] (5461 slots) master
M: 04cdccf3cf41e2e590d9883634874c2fc8d94796 127.0.0.1:6379
   slots:[10923-16383] (5461 slots) master
M: 2ceb444b77d974515aed477b4ae941e361995ae2 127.0.0.1:6378
   slots:[5461-10922] (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

master/slave 構成は `–cluster-replicas` オプションで設定する。

Redis-Cluster の Failover 機能を試す

master (192.168.10.1:6379) に対する slave (192.168.10.2:6380) を設定し Failover を試してみる。

$ ruby ./redis-trib.rb add-node --slave 192.168.10.2:6380 192.168.10.1:6379

slave 追加時点の構成は以下。

$ redis-cli -p 6379 -c CLUSTER NODES
5018bdc02898b53c752e3b7df91e46a8aad6d4af 192.168.10.1:6379 master - 0 1481017459922 3 connected 0-5460
622c471ff316f9a20887ce92308fcecd7904ed61 192.168.10.2:6380 slave 5018bdc02898b53c752e3b7df91e46a8aad6d4af 0 1481017459982 1 connected
57ba77cbfa6b7fa831946a60e77c89e76aa88771 192.168.10.2:6379 myself,master - 0 0 1 connected 10923-16383
da9757c83d88a6d84f3e68d3e4cfb2ea0e7531d4 192.168.10.3:6379 master - 0 1481017461927 2 connected 5461-10922

master (192.168.10.1:6379) を落としてみる。

$ redis-cli -p 6379 DEBUG SEGFAULT
Error: Server closed the connection

Failover が働き slave が master に昇格していることを確認。

$ redis-cli -p 6379 -c CLUSTER NODES
5018bdc02898b53c752e3b7df91e46a8aad6d4af 192.168.10.1:6379 master,fail - 0 1481017459982 1 disconnected
622c471ff316f9a20887ce92308fcecd7904ed61 192.168.10.2:6380 master - 1481017459985 4 connected 0-5460
57ba77cbfa6b7fa831946a60e77c89e76aa88771 192.168.10.2:6379 myself,master - 0 0 1 connected 10923-16383
da9757c83d88a6d84f3e68d3e4cfb2ea0e7531d4 192.168.10.3:6379 master - 0 1481017461927 2 connected 5461-10922

落としたノードは serviceコマンドなどで再起動すると昇格した master に対する slave となる。
この仕組みのため master が N 台の場合, 対応する slave も N 台用意する必要がある。

Redis-Cluster のノードを Upgrade する

DEBUG SEGFAULT コマンドで Failover 機能の確認を行ったが, 稼働中の Redis-Cluster のノードをバージョンアップや設定変更する場合にこの方法は適切ではない。
Redis cluster tutorial [1] では, まず slave を再起動で更新してから master は1台ずつ手動で CLUSTER FAILOVER コマンドにより slave 化し再起動する手順が書かれている。

$ redis-cli -p 6379 -c CLUSTER FAILOVER

Redis-Cluster 構築時の Troubleshooting

redis-trib.rb 実行時に以下のエラーが起きた時は 各ノードで flushall / cluster reset する。

[ERR] Node 127.0.0.1:6379 is not empty. Either the node already knows other nodes (check with CLUSTERNODES) or contains some key in database 0.
$ redis-cli -p 6379
127.0.0.1:6379> flushall
127.0.0.1:6379> cluster reset
127.0.0.1:6379> exit

おわりに

macOS でも上記とほとんど同じ手順でクラスターを構築できます。 (brew でインストール後に /usr/local/etc/redis.conf を複製し設定変更)
Lua によるサーバサイドスクリプティングを試しているので近々書くかもしれません。


[1] Redis cluster tutorial
[2] [err]: Test replication partial resync: ok psync (diskless: yes, reconnect: 1) について
[3] Redis Clusterの操作を簡単にするredis-trib.rbの使い方
[4] Redis Cluster の構築と利用(Redis 3.0.0)
[5] redis3.2.0以降はprotect-modeが有効
[6] Redis 本番障害から学んだコードレビューの勘所
[7] Redis を LRU キャッシュとして使う
[8] Redis sentinel vs clustering
[9] How to recover redis data from snapshot(rdb file) copied from another machine?
[10] Redis Cluster の運用とモニタリング/監視のコツ