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 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コマンドは、公式ページのここで確認できます。
動作確認
設定完了したので、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投稿を見つけて。
Since #Redis 6.0, systemd support is enabled only if libsystemd-dev has been detected at build time.
— dek 🚀 (@dekonnection) May 20, 2020
If you encounter a timeout when doing systemctl start/restart, check that first and rebuild ;)
See: https://t.co/aup7f0H7Wr
下記のページを見ると、 Type=notify
を利用するには、コンパイル時にUSE_SYSTEMDという変数を設定が必要であったようです。
Auto-detect and link libsystemd at compile-time
そのため今回は、Systemdでのスタートアップタイプを Type=simple
として、対応しています。