この記事の内容
- redisの準備
- redis-sentinelの準備
- perlから利用する方法
を記載します。
sentinelをアプリからどう使うか、がキモです。
sentinelの詳細については、Redis Sentinel Documentationを御覧ください。
はじめに
今回は、1台のサーバに、
- redis 2セット(master / slave)
- sentinel 3セット
を準備します。
OSはCentOS 7系を想定します。
商用では、最低限
- master(redis + sentinel)
- slave(redis + sentinel)
- sentinel(sentinel)
サーバの3台が必要です。
sentinelプロセスは、各サーバで1つずつ動作させます。
redisのセットアップ
パッケージをインストールします。
$ sudo yum install redis
/etc/redis.confと、/etc/redis-sentinel.confが生成されます。
今回は実験なので、ホームディレクトリ配下にworking directoryを作成します。
$ cd
$ mkdir redis-work
$ cd redis-work
master/slave用のコンフィグを2つ作ります。
最初は16379をmaster, 16380をslaveにします。
(master / slaveはsentinelにより動的に変更されます)
$ vim 16379.conf
bind 127.0.0.1
port 16379
daemonize yes
pidfile /tmp/redis_16379.pid
slave-read-only yes
$ vim 16380.conf
bind 127.0.0.1
port 16380
daemonize yes
pidfile /tmp/redis_16380.pid
slaveof 127.0.0.1 16379
slave-read-only yes
この設定ファイルを用いて、起動します。
$ redis-server 16379.conf
$ redis-server 16380.conf
正常にmaster / slaveになっているか確認しましょう。
$ redis-cli -p 16379 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=16380,state=online,offset=1,lag=1
master_repl_offset:1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:0
$ redis-cli -p 16380 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:16379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_repl_offset:15
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
正常に動いていますね。
redis sentinelのセットアップ
yumでredisをインストールすると、redis-sentinelというコマンドも
インストールされます。
実態はただのredis-serverへのsymlinkです。
つまり動くバイナリは同じものです。
が
redisは起動時のargv[0]をみて、動作モードを変えるため、sentinelを起動するときには、
- redis-sentinelコマンドを使う
- redis-server --sentinel オプションを使う
のどちらかで起動する必要があります。
以上蛇足でした。
設定に入ります。
同じworking directoryで、sentinel用のコンフィグを3つ作ります。
(違うのはportとpidだけです)
$ cd ~/redis-work/
$ vim sentinel1.conf
bind 127.0.0.1
port 26379
daemonize yes
pidfile /tmp/redis_sentinel1.pid
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor servers1 127.0.0.1 16379 2
sentinel down-after-milliseconds servers1 2500
sentinel failover-timeout servers1 10000
$ vim sentinel2.conf
bind 127.0.0.1
port 26380
daemonize yes
pidfile /tmp/redis_sentinel2.pid
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor servers1 127.0.0.1 16379 2
sentinel down-after-milliseconds servers1 2500
sentinel failover-timeout servers1 10000
$ vim sentinel3.conf
bind 127.0.0.1
port 26381
daemonize yes
pidfile /tmp/redis_sentinel3.pid
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor servers1 127.0.0.1 16379 2
sentinel down-after-milliseconds servers1 2500
sentinel failover-timeout servers1 10000
さて、この後起動するのですが、
sentinelはコンフィグを自動的に書き換えますので、
その点は留意しておく必要があります。
$ redis-sentinel sentinel1.conf
$ redis-sentinel sentinel2.conf
$ redis-sentinel sentinel3.conf
ちょっと経つと、3ファイルともコンフィグが書き換わってます。
$ cat sentinel1.conf
bind 127.0.0.1
port 26379
daemonize yes
pidfile "/tmp/redis_sentinel1.pid"
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel myid 15c12113c628851836e39a1de9bf579879fd5005
sentinel deny-scripts-reconfig yes
sentinel monitor servers1 127.0.0.1 16379 2
# Generated by CONFIG REWRITE
dir "/home/vagrant/redis-work"
maxclients 4064
sentinel down-after-milliseconds servers1 2500
sentinel failover-timeout servers1 10000
sentinel config-epoch servers1 19
sentinel leader-epoch servers1 19
sentinel known-slave servers1 127.0.0.1 16380
sentinel known-sentinel servers1 127.0.0.1 26381 d00ffb8bb57f4c78f825dba247f0d18d155d2de2
sentinel known-sentinel servers1 127.0.0.1 26380 2b79180a7f9ba77012461d0e522a27d838927ea5
sentinel current-epoch 19
こんな感じで、もとの設定ファイルでは、masterの接続先のみを記述したにもかかわらず、
自分以外のsentinelとslaveの情報がconfigに追記されていることがわかります。
これでsentinelの準備は完了です。
redis-sentinelの利用
今回はperlのRedisモジュールである、Redis::Fastを用います。
処理速度的にはRedis::Jetが早いのですが、sentinel対応していないので・・・。
ということで、sentinelを使う場合は通常の接続方法と違って、
sentinelサーバの接続先を記載します。
use strict;
use warnings;
use 5.020;
use Redis::Fast;
my $redis = Redis::Fast->new(
sentinels => [qw/
127.0.0.1:26379
127.0.0.1:26380
127.0.0.1:26381
/],
service => "servers1",
sentinels_write_timeout => 1,
sentinels_read_timeout => 1,
sentinels_cnx_timeout => 0.1,
reconnect => 10, every => 300_000
);
my $i = 0;
my $key = "hoge";
while (1) {
eval {
$redis->set($key, $i);
say $redis->get($key);
};
if ($@) {
warn "$@";
next;
}
$i++;
sleep(1);
}
キモとなるのは、
- new時にsentinelsでsentilelサーバ群の接続先を書くこと
- redis-serverではない。
- serviceに、sentinelで指定したを指定すること
- reconnect(秒数), every(ミリ秒)を適切に設定すること
- 設定しないと再接続しない
です。
実験
プログラムを動かします。
$ perl test-sentinel.pl
0
1
2
...
別シェルを起動して、現在のmasterをkillします。
$ redis-cli -p 26379 SENTINEL get-master-addr-by-name servers1
1) "127.0.0.1"
2) "16379"
$ pkill -f 127.0.0.1:16379
すると、3秒程度で、
$ redis-cli -p 26379 SENTINEL get-master-addr-by-name servers1
1) "127.0.0.1"
2) "16380"
と、もう方系がmasterに昇格します。
次に、落としたredisを再起動します。
$ redis-server 16379.conf
$ redis-cli -p 16379 info replication
# Replicationn
role:master
connected_slaves:0
master_replid:621891c20bbffd2019a2980976ca212c792ca39f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
このように、最初はmasterで立ち上がってきますが、
ちょっと経って再度チェックすると、
$ redis-cli -p 16379 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:16380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:97189
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:4fc10a2b219a9dcaf13a14cbc41652032733706a
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:97189
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:90363
repl_backlog_histlen:6827
このように、slaveとなっています。
このときのプログラムの出力を確認してほしいのですが、
途切れなく数値が続いているはずです。
注意点
方系を落とし、落とした方を再起動したあと、
slaveになる前にもう方系をkillすると、うまくfailoverしません。
実験時には、2台のredisがmaster / slave の状態になっていることを確認し、
master側をkillしましょう。
終わりに
redis-sentinelは、sentinelサーバがつなぐべきmasterを教えてくれるため、
例えばkeepalivedでVIPをもたせて、アプリ側でそちらにつなぐ、
ようなことは不要です。slaveのmaster化も勝手にやってくれますし。
sentinel対応してくれている、モジュールの開発者様様ですね。