Redis ReplicationとSentinelの設定方法を確認

RedisのReplicationとSentinelによる自動フェイルオーバーの設定方法について確認したメモです。

環境情報

  • CnetOS
    • 8.1.1911
  • Redis
    • 6.0.3
  • Sentinel
    • 2

構成

Masterが1台、Replicaが1台、Sentinelが3台という環境です。

Master/Replica IPアドレス Redis port Sentinel port
Server1 Master 192.168.0.10 6379 26379
Server2 Replica 192.168.0.20 6379 26379
Server3 - 192.168.0.30 - 26379

それぞれサーバーでは、Redisインストール済として、作業を進めます。

Redis ACLの準備

Redis6以降では、Access Control List(ACL)という、認証と認可の概念ができたようです。ユーザーとパスワードによる認証機能と、Redis機能の権限を認可する設定となります。

今回、Replication用とSentinel用で専用ユーザーを作成するのですが、デフォルトのRedis設定ですと、ACL設定情報はメモリー上にしか記録されないので、設定永続化のためにACL fileの有効化を行います。RedisコンフィグファイルのACL file部分を、以下のようにアンコメントアウトします。

# Using an external ACL file
#
aclfile /etc/redis/users.acl

なお、指定したACL fileが存在しないとRedis起動時に怒られるため、空のファイルを用意しておきます。

また、Redis5まであったrequirepassパラメーターによる認証機能は、defaultユーザーのパスワードといった形で残っています。初期時点ではパスワード未設定となっているため、設定しておきます。

> acl getuser default
1) "flags"
2) 1) "on"
   2) "allkeys"
   3) "allcommands"
   4) "nopass"
3) "passwords"
4) (empty array)
5) "commands"
6) "+@all"
7) "keys"
8) 1) "*"
>
> acl setuser default >passwd
OK
>
> acl getuser default
1) "flags"
2) 1) "on"
   2) "allkeys"
   3) "allcommands"
3) "passwords"
4) 1) "0d6be69b264717f2dd33652e212b173104b4a647b7c11ae72e9885f11cd312fb"
5) "commands"
6) "+@all"
7) "keys"
8) 1) "*"
>
> acl save
OK

パスワード文字列はハッシュ化されて保存されるので、コンフィグファイルにパスワード文字列を直書きしていた方法と比較すると、セキュアになったんだなと思いますね。

Redis Replicationの設定

Replication用ユーザーの作成

MasterとReplicaとなるRedisサーバーに、Replication用ユーザーを追加します。必要となる権限については、公式ドキュメントに記載あるので、それを参考にACLコマンドを実行します。

ACL rules for Sentinel and Replicas

> ACL setuser replica-user >passwd +psync +replconf +ping on
OK
>
> acl getuser replica-user
1) "flags"
2) 1) "on"
3) "passwords"
4) 1) "0d6be69b264717f2dd33652e212b173104b4a647b7c11ae72e9885f11cd312fb"
5) "commands"
6) "-@all +psync +ping +replconf"
7) "keys"
8) (empty array)
>
> acl save
OK

Replication用設定の実施

ReplicaとなるRedisサーバーに、Replication用のコンフィグ設定を実施します。

下記の公式ドキュメントを読みつつ。

Redis Replication

下記Redisコンフィグ内Replication関連のパラメーターを舐めていって、必要そうなパラメーターを設定します。

Redis configuration file example.

こんな感じでしょうか。

パラメーター
replicaof 192.168.0.10 6379
masteruser replica-user
masterauth passwd
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-diskless-load disabled
repl-ping-replica-period 10
repl-timeout 60
repl-disable-tcp-nodelay no
replica-priority 100
min-replicas-to-write 0
min-replicas-max-lag 10

コンフィグ修正後にRedisプロセスを再起動します。以下はReplica設定できた時の出力ログです。

3006:S 28 May 2020 19:23:26.105 * MASTER <-> REPLICA sync started
3006:S 28 May 2020 19:23:26.105 * Non blocking connect for SYNC fired the event.
3006:S 28 May 2020 19:23:26.109 * Master replied to PING, replication can continue...
3006:S 28 May 2020 19:23:26.115 * Trying a partial resynchronization (request 386938b145b9563d964075b264444e64a3904223:71).
3006:S 28 May 2020 19:23:26.117 * Successful partial resynchronization with master.
3006:S 28 May 2020 19:23:26.117 * MASTER <-> REPLICA sync: Master accepted a Partial Resynchronization.

masterとなるRedisサーバー上での確認コマンド結果。

$ redis-cli -a passwd info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.0.20,port=6379,state=online,offset=285379,lag=1
master_replid:7613adb012e08537a3c3762e005a7bfe372b8929
master_replid2:0b4b076ce938d4dcf28dca880e4703cf8c642ce1
master_repl_offset:285520
master_repl_meaningful_offset:285520
second_repl_offset:197889
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1716
repl_backlog_histlen:283805

Redis Sentinelの設定

続いてSentinelの設定を実施します。Sentinelの設定は3台の全てのサーバーに同一設定をします。

Sentinel用ユーザーの作成

Setinel用ユーザーを作成します。必要な権限は公式ドキュメントに記載ある通りです。

> acl setuser sentinel-user >passwd +client +subscribe +publish +ping +info +multi +slaveof +config +client +exec on
OK
>
> acl getuser sentinel-user
1) "flags"
2) 1) "on"
3) "passwords"
4) 1) "0d6be69b264717f2dd33652e212b173104b4a647b7c11ae72e9885f11cd312fb"
5) "commands"
6) "-@all +client +subscribe +multi +info +exec +config +slaveof +ping +publish"
7) "keys"
8) (empty array)
>
> acl save
OK

Setinel向けコンフィグの作成

Sentinel向けのコンフィグファイルを作成します。まずはデフォルトパスにあるコンフィグファイルをコピーしてきて。

$ cp /original/path/to/sentinel.conf /etc/redis/sentinel.conf

各パラメーターを編集します。

パラメーター
protected-mode no
port 26379
daemonize no
logfile "/var/log/redis/sentinel.log"
sentinel monitor mymaster 192.168.0.10 6379 2
sentinel auth-pass mymaster passwd
sentinel auth-user mymaster sentinel-user
sentinel down-after-milliseconds mymaster 30000
requirepass passwd
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000

パーミッションを変更しておきます。

$ sudo chown redis:redis /etc/redis/sentinel.conf

SentinelプロセスのSystemd起動設定

SetinelプロセスをSystemdに登録します。

/etc/systemd/system/redis-sentinel.service

[Unit]
Description=redis-sentinel
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/redis-server /etc/redis/sentinel.conf --sentinel
ExecStop=/usr/local/bin/redis-cli -p 26379 shutdown
Restart=always
User=redis
Group=redis
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

ファイルパーミッションを整えたのち、Sentinelを起動します。

$ sudo chown root:root /etc/systemd/system/redis-sentinel.service
$ sudo chmod 644 /etc/systemd/system/redis-sentinel.service
$ sudo systemctl daemon-reload
$ sudo systemctl enable redis-sentinel
$ sudo systemctl start redis-sentinel

確認

設定状態を確認します。

$ redis-cli -a passwd -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.0.10:6379,slaves=2,sentinels=3

利用可能なSentinelコマンドは、公式ページのここで確認できます。

Sentinel commands

動作確認

設定完了したので、Failover時の動作を確認してみます。

MasterとなっているRedisプロセスを停止すると、ReplicaとなっていたRedisがMasterとして動作し始めます。以下は、Replicaだったサーバーでの確認コマンド。roleがmasterとなっており、slave数は0。

$ redis-cli -a passwd info replication
# Replication
role:master
connected_slaves:0
master_replid:7200db25ba1fc9b482739e732ab16f7677864bf1
master_replid2:7613adb012e08537a3c3762e005a7bfe372b8929
master_repl_offset:309597
master_repl_meaningful_offset:309597
second_repl_offset:298436
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:218357
repl_backlog_histlen:91241

この状況より、先程停止したRedisプロセスを再開すると、そのサーバーはReplicaとして起動します。以下はその確認コマンド。

$ redis-cli -a passwd info replication
# Replication
role:slave
master_host:192.168.0.20
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:340936
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:7200db25ba1fc9b482739e732ab16f7677864bf1
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:340936
master_repl_meaningful_offset:340936
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:340773
repl_backlog_histlen:164

その他

今回の環境では、RedisをSystemd経由で管理することがなかなかできず、色々とハマりました。Systemd経由にてRedisおよびSentinelを起動しようとすると、Redisの再起動が繰り返される動作となっていました。

原因ですが、以下のtwitter投稿を見つけて。

下記のページを見ると、 Type=notify を利用するには、コンパイル時にUSE_SYSTEMDという変数を設定が必要であったようです。

Auto-detect and link libsystemd at compile-time

そのため今回は、Systemdでのスタートアップタイプを Type=simple として、対応しています。