Redis Sentinel
Redis
はオープンソースのインメモリ型データ構造ストアであり、組み込みのトランザクション、レプリケーションを備えています。Redis はマスターとレプリカのRedis Replication 構成を取れますが、高可用性に重点を置いた別の展開構成として Redis Sentinel
があります。Redis Sentinel はマスターサーバーの障害を検知し、動的にレプリカをマスターに昇格させることができます。マスターとレプリカは常に同じデータを持つように構成されます。Redis にはマスターを複数持ち、データをシャーディングし複数のサーバーに分散可能な Redis Cluster
もあります。Redis Cluster はデータを分散するため、負荷を分散できる長所がありますが、高可用性を保つにはそれぞれのマスターのレプリカが必要になり、要件によっては冗長すぎる構成になります。Redis Sentinel は最小構成 3 台で実現できる容易に高可用性を担保できるバランスの良い機能です。
Redis Sentinel のプロセスを 3 つ以上にすれば、Redis Server は マスターとレプリカの 2 台構成でも可能ですが、本記事では 3 台構成の例を紹介します。
本記事は以下の文書を参考にし、初めての方が容易に Redis Sentinel が構成できることを目的としています。60 分以内に、Redis Sentinel の構成をインストールして確認することができます。
インストールされる構成
アカマイ社が展開するクラウドサービスのマーケットプレイスを使って安価なコストで Redis Sentinel をデプロイします。5 台まで選択できますが、今回は 3 台構成とします。展開されたコンピュートインスタンス (Linode) は Private IP を使って互いに通信します。マーケットプレイスはクラスタ環境をワンクリックで設定できるスクリプトが用意されており、Redis Sentinel はその中の一つです。
インストールされるのは、Redis 公式サイト https://redis.io/docs/management/sentinel/ の basic setup with three boxes のパターンになります。
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
Configuration: quorum = 2
全体は3つのノードで構成され、1つの Master (M)
ノードと2つの Replica (R)
ノードとして動作します。それぞれのノードには Sentinel (S)
のエージェントが動作しており、Sentinel がどのサーバーが Master となるべきかを決定します。Sentinel プロセスの多数決投票が行われ、この構成であれば 2 つが合意したサーバーをマスターに決定します (quorum = 2)。
インストールされるプロセスとコマンド
マーケットプレイスからインストールされる主な構成要素は以下となります。
- redis server
- redis sentinel
- redis-cli
- firewalld
firewalld は Redis サーバーを保護するために導入します。不要であれば止めることができます。今回は不必要なアクセスを許可しないため、firewalld を継続利用します。
インストール
www.linode.com から Linode Console にログインし、Marketplace から Redis Sentinel を選択します。
Linode API Token と sudo コマンドが利用できるユーザーアカウント名を入力します。
トークンの取得方法は以下を参考にしてください。
次に Redis サーバーと TLS 接続するための自己証明書に関する情報を入力します。
クラスタ設定をします。SSH Keys を全てのノードに加えるようにします。クラスタは 3 台構成を選択します。
Image は Ubuntu となります。Region は日本を選択します。
次のコンピュートリソースのモデルを選択します。Redis はインメモリのデータストアになりますので High Memory のタイプが推奨ですが、今回は Linode 2GB (2GB メモリ)を選択します。
作成するインスタンスの Root パスワードを入力します。必要であれば、User の SSH Key を選択します。設定しておけばセキュアに、かつ、ログインが容易になります。
Create Linode のボタンを押します。このワンクリックで 3 ノードのクラスタが作成できます。
Create Using Command Line をクリックすれば、Linode API (cURL) と Linode CLI のシンタックスが表示されます。内部で呼び出される StackScript の ID と入力値なども見ることができます。
23 分ほどでインストレーションが終了しました。
確認方法
新規作成されたインスタンスの名前を見ます。ラベル名の末尾に 1/2/3 のいずれかの数字が入っています。インスタンスの (Public) IP Address をコピーします。
ssh でログインします。
% ssh user@{Public_IP_Address}
/etc/hosts
には Redis Sentinel Cluster の3つの Private IP が登録されています。ホスト名を使って、どのようにサーバーの役割が変わっていくかに注目すると分かりやすくなります。
# Redis
192.168.198.87 redissentinel-tokyo1
192.168.198.103 redissentinel-tokyo2
192.168.198.112 redissentinel-tokyo3
# END redis servers
Linode Console には Private IP が登録されています。
以下のドキュメントに記載あるように、作成したユーザーアカウントの配下の ~/.deployment-secrests.txt
に Redis サーバーにアクセスできる情報が書かれています。root ユーザーの配下ではないので注意ください。
ユーザー名が User の場合の例です。
user@redissentinel-tokyo1:~$ cat .deployment-secrets.txt
# BEGIN ANSIBLE MANAGED BLOCK
# system user
user: user
password: YOUR_ACCOUNT_LINUX_PASSWORD
# redis password
redis-cli --askpass --tls --cacert /etc/redis/tls/ca.crt:
y+8erSZr9YHAUIzA19zkxaS/8d+kjx4tMJXXXXXXXXXX
# END ANSIBLE MANAGED BLOCK
ファイル内に Redis サーバーに接続するためのパスワードが記載されています。環境変数 REDISCLI_AUTH
を使えば redis-cli
コマンドを利用するときにパスワードの入力を省略できます。~/.bashrc
に登録すればログインすると動的に設定されます。なお、環境変数の設定はこの後の説明のため root ユーザーの環境で実施しますが、一般ユーザー環境でも実行は可能です。
すぐに設定内容を反映するように、 source
コマンドで有効にします。
source .bashrc
パスワードの取り扱いに注意してください。
Master (redissentinel-tokyo1) からの接続テスト
ここまでの作業で、redis-cli
を使うまでの準備が整いました。~/.deployment-secrests.txt
に記載されているコマンドを起動します。--askpass
は省略可能です。/etc/redis/tls/ca.crt
は root 権限でないとアクセスできないようになっていますので、一般ユーザーで実行するにはファイルをアクセスできる場所にコピーしてください。
redis-cli --tls --cacert /etc/redis/tls/ca.crt
ログインに成功したら、ping
コマンドを打ちます。PONG
が返却されれば動作できています。
root@redissentinel-tokyo1:~# redis-cli --tls --cacert /etc/redis/tls/ca.crt
127.0.0.1:6379> ping
PONG
info replication
コマンドを打つと、role:master
が見えます。これはこのサーバーがマスターサーバーであることを意味します。
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.198.112,port=6379,state=online,offset=397294,lag=1
slave1:ip=192.168.198.103,port=6379,state=online,offset=397294,lag=1
master_failover_state:no-failover
master_replid:fac9e97e4769636aa327dbdf17c54bbfe8e2a5dc
master_replid2:e545c6cdcac628dbf0851c2521c3c8efa6b9df07
master_repl_offset:397581
second_repl_offset:5818
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:5818
repl_backlog_histlen:391764
データを操作します。scott
キーに tiger
のデータを挿入できました。
127.0.0.1:6379> get scott
(nil)
127.0.0.1:6379> set scott tiger
OK
127.0.0.1:6379> get scott
"tiger"
127.0.0.1:6379> quit
次のようにポート 26379 を使えば、Sentnel にも接続できます。
redis-cli --tls --cacert /etc/redis/tls/ca.crt -p 26379
一つ目のレプリカ (redissentinel-tokyo2) からの接続テスト
-h
オプションを使って、ホストを切り替えます。
redis-cli -h redissentinel-tokyo2 --tls --cacert /etc/redis/tls/ca.crt
ping
は動作しています。role:slave
が表示されています。
root@redissentinel-tokyo1:~# redis-cli -h redissentinel-tokyo2 --tls --cacert /etc/redis/tls/ca.crt
redissentinel-tokyo2:6379> ping
PONG
redissentinel-tokyo2:6379> info replication
# Replication
role:slave
master_host:192.168.198.87
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:429878
slave_repl_offset:429878
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:fac9e97e4769636aa327dbdf17c54bbfe8e2a5dc
master_replid2:e545c6cdcac628dbf0851c2521c3c8efa6b9df07
master_repl_offset:429878
second_repl_offset:5818
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:68
repl_backlog_histlen:429811
redissentinel-tokyo2:6379>
データを操作します。Read (get) はできますが、Write (set) はできません。Redis のレプリカサーバーは Write できないので、Read Only 用途としてサービスを提供できます。
redissentinel-tokyo2:6379> get scott
"tiger"
redissentinel-tokyo2:6379> set scott lion
(error) READONLY You can't write against a read only replica.
redissentinel-tokyo2:6379>
2つ目のレプリカ (redissentinel-tokyo3) からの接続テスト
-h
オプションを使って、ホストを切り替えます。
redis-cli -h redissentinel-tokyo3 --tls --cacert /etc/redis/tls/ca.crt
ping
は動作しています。role:slave
が表示されています。
root@redissentinel-tokyo1:~# redis-cli -h redissentinel-tokyo3 --tls --cacert /etc/redis/tls/ca.crt
redissentinel-tokyo3:6379> ping
PONG
redissentinel-tokyo3:6379> info replication
# Replication
role:slave
master_host:192.168.198.87
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:445061
slave_repl_offset:445061
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:fac9e97e4769636aa327dbdf17c54bbfe8e2a5dc
master_replid2:e545c6cdcac628dbf0851c2521c3c8efa6b9df07
master_repl_offset:445061
second_repl_offset:5818
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:68
repl_backlog_histlen:444994
データを操作します。Read (get) はできますが、Write (set) はできません。
redissentinel-tokyo3:6379> get scott
"tiger"
redissentinel-tokyo3:6379> set scott tiger3
(error) READONLY You can't write against a read only replica.
ファイル構成
Redis のコンフィグファイル、ログファイルを確認します。
/etc/redis/
root@redissentinel-tokyo1:~# cd /etc/redis
root@redissentinel-tokyo1:/etc/redis# ls -l
total 252
-rw-r----- 1 redis redis 107058 Jun 29 14:06 redis.conf
-rw-r--r-- 1 redis redis 106589 Dec 16 2022 redis.conf.bak
-rw-r----- 1 redis redis 15699 Jun 29 14:07 sentinel.conf
-rw-r--r-- 1 redis redis 14894 Jun 29 14:03 sentinel.conf.bak
drwxr-xr-x 2 redis redis 4096 Jun 29 14:06 tls
root@redissentinel-tokyo1:/etc/redis#
Redis Replication のページにレプリカの maxmemory について注意事項が書かれています。レプリカは maxmemory
を無視し、マスターとレプリカの一貫性を保つように初期設計されています。デフォルトではレプリカはevictしないので、maxmemoryで設定されたメモリよりも多くのメモリを使用してしまう可能性があります(レプリカでより大きくなるバッファがあったり、データ構造でより多くのメモリを使用したりすることがあるためです)。レプリカを監視し、マスタが設定されたmaxmemory設定に到達する前に、実際にメモリ不足の状態に陥ることがないように、レプリカに十分なメモリがあることを確認してください。
この動作を変更するには、レプリカがmaxmemoryを無視しないようにします。使用する設定ディレクティブは以下の通りです:
replica-ignore-maxmemory no
現在の設定は redis-cli でも確認できます。
root@redisclient:~# redis-cli -h redissentinel-tokyo1 --tls --cacert redissentinel-tokyo_ca.crt
redissentinel-tokyo1:6379> config get replica-ignore-maxmemory
1) "replica-ignore-maxmemory"
2) "yes"
/var/log/redis/
root@redissentinel-tokyo1:/etc/redis# cd /var/log/redis
root@redissentinel-tokyo1:/var/log/redis# ls -l
total 12
-rw-rw---- 1 redis adm 3824 Jun 29 14:07 redis-sentinel.log
-rw-rw---- 1 redis adm 7620 Jun 29 14:29 redis-server.log
プロセス
redis-server
root@redissentinel-tokyo1:/var/log/redis# lsof +c 15 -i :6379 | grep redis-server
redis-server 21223 redis 6u IPv4 88791 0t0 TCP localhost:redis (LISTEN)
redis-server 21223 redis 7u IPv6 88792 0t0 TCP localhost:redis (LISTEN)
redis-server 21223 redis 8u IPv4 88793 0t0 TCP redissentinel-tokyo1:redis (LISTEN)
redis-server 21223 redis 9u IPv4 88970 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo1:56444 (ESTABLISHED)
redis-server 21223 redis 10u IPv4 88985 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo1:56458 (ESTABLISHED)
redis-server 21223 redis 11u IPv4 88986 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo3:38680 (ESTABLISHED)
redis-server 21223 redis 12u IPv4 88988 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo2:57826 (ESTABLISHED)
redis-server 21223 redis 13u IPv4 88993 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo3:38692 (ESTABLISHED)
redis-server 21223 redis 14u IPv4 88995 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo2:35624 (ESTABLISHED)
redis-server 21223 redis 15u IPv4 88996 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo2:35634 (ESTABLISHED)
redis-server 21223 redis 16u IPv4 89541 0t0 TCP redissentinel-tokyo1:redis->redissentinel-tokyo3:38696 (ESTABLISHED)
redis-sentinel
root@redissentinel-tokyo1:/etc/redis# lsof +c 15 -i :26379
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
redis-sentinel 21283 redis 6u IPv4 88959 0t0 TCP localhost:26379 (LISTEN)
redis-sentinel 21283 redis 7u IPv6 88960 0t0 TCP localhost:26379 (LISTEN)
redis-sentinel 21283 redis 8u IPv4 88961 0t0 TCP redissentinel-tokyo1:26379 (LISTEN)
redis-sentinel 21283 redis 15u IPv4 88981 0t0 TCP redissentinel-tokyo1:54848->redissentinel-tokyo3:26379 (ESTABLISHED)
redis-sentinel 21283 redis 16u IPv4 88982 0t0 TCP redissentinel-tokyo1:60110->redissentinel-tokyo2:26379 (ESTABLISHED)
redis-sentinel 21283 redis 17u IPv4 89475 0t0 TCP redissentinel-tokyo1:26379->redissentinel-tokyo3:60696 (ESTABLISHED)
redis-sentinel 21283 redis 18u IPv4 89477 0t0 TCP redissentinel-tokyo1:26379->redissentinel-tokyo2:57536 (ESTABLISHED)
サービス自動起動の確認
root@redissentinel-tokyo1:~# systemctl is-enabled redis-server
disabled
root@redissentinel-tokyo1:~# systemctl is-enabled redis-sentinel
disabled
サーバーが停止したときは手動で起動することを前提としています。自動起動するには、以下のようにします。
root@redissentinel-tokyo1:~# systemctl enabled redis-server
root@redissentinel-tokyo1:~# systemctl enabled redis-sentinel
Redis Client の設定
Redis Server 内で redis-cli を使って接続確認をしましたが、多くのケースでは別のサーバーで動作するアプリケーションから Redis Server に接続されます。Linode インスタンスを追加し、追加されたサーバーをアプリケーションと見なして Redis に接続できることを確認します。
接続確認するだけなので、一番安価な $5 プランの Nanode 1GB を選択します。Region は Redis Server を構築した場所と同じ Tokyo を選択します。Distributeion も Redis Server との操作性の互換を重視し、Ubuntu にします。
Public IP を使わずに Redis Server にアクセスしたいので、Private IP をオンにします。
必要なアップデートをします。
apt update && apt upgrade
Redis Server の IP アドレスをホストファイルに登録して、この後、ホスト名で redis-cli を使えるように準備します。
# Redis
192.168.198.87 redissentinel-tokyo1
192.168.198.103 redissentinel-tokyo2
192.168.198.112 redissentinel-tokyo3
# END redis servers
ping で疎通確認します。
root@redisclient:~# ping redissentinel-tokyo1
PING redissentinel-tokyo1 (192.168.198.87) 56(84) bytes of data.
64 bytes from redissentinel-tokyo1 (192.168.198.87): icmp_seq=1 ttl=60 time=0.428 ms
64 bytes from redissentinel-tokyo1 (192.168.198.87): icmp_seq=2 ttl=60 time=0.569 ms
Redis Server の /etc/redis/tls/ca.crt
をコピーして、Client の Linode サーバーにコピーします。redis-cli で同じ証明書情報を使う必要があります。
root@redissentinel-tokyo1:~# cat /etc/redis/tls/ca.crt
redis-cli をインストールします。
apt install redis-tools
redis-cli で接続を試みます。
root@redisclient:~# redis-cli -h redissentinel-tokyo1 --tls --cacert redissentinel-tokyo_ca.crt
Could not connect to Redis at redissentinel-tokyo1:6379: No route to host
No route to host
は Redis Sentinel のサーバーにインストールされている firewalld
がブロックしているからです。そのため、firewalld に クライアントの Private IP を登録する必要があります。
Private IP アドレスを取得します。 192.168.139.199
になります。
root@redisclient:~# ip -4 a show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
inet {Public_IP}/24 brd XXX.XXX.XXX.XXX scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.139.199/17 brd 192.168.255.255 scope global eth0
valid_lft forever preferred_lft forever
Linode Console の Network タブからも同じ情報が見られます。
得られた Private IP を Redis Server で動いている firewalld に設定します。
firewalld の設定
Redis Master サーバーにログインします。firewalld
が起動していることを確認します。
root@redissentinel-tokyo1:/etc/firewalld# ps auxw|egrep firewalld
root 20936 0.0 1.9 128280 39212 ? Ssl Jun29 0:00 /usr/bin/python3 /usr/sbin/firewalld --nofork --nopid
firewalld の確認には firewall-cmd が使えます。
root@redissentinel-tokyo1:/etc/firewalld# firewall-cmd -V
1.1.1
root@redissentinel-tokyo1:/etc/firewalld# firewall-cmd --state
running
有効なゾーン設定を確認します。
root@redissentinel-tokyo1:/etc/firewalld# firewall-cmd --get-active-zone
internal
sources: 192.168.198.87 192.168.198.103 192.168.198.112
internal zone の設定が有効になっていることが分かります。この中に Redis Sentinel サーバーの Public IP のアドレスが登録されている。
firewalld の設定ファイルは /etc/firewalld/
配下にあります。
root@redissentinel-tokyo1:/etc/firewalld# pwd
/etc/firewalld
root@redissentinel-tokyo1:/etc/firewalld# ls -l
total 32
-rw-r--r-- 1 root root 2485 Jun 29 14:03 firewalld.conf
drwxr-xr-x 2 root root 4096 Mar 28 2022 helpers
drwxr-xr-x 2 root root 4096 Mar 28 2022 icmptypes
drwxr-xr-x 2 root root 4096 Mar 28 2022 ipsets
-rw-r--r-- 1 root root 268 Mar 28 2022 lockdown-whitelist.xml
drwxr-xr-x 2 root root 4096 Mar 28 2022 policies
drwxr-xr-x 2 root root 4096 Mar 28 2022 services
drwxr-xr-x 2 root root 4096 Jun 29 14:04 zones
zones の下に internal.xml があります。
root@redissentinel-tokyo1:/etc/firewalld# cd zones
root@redissentinel-tokyo1:/etc/firewalld/zones# ls
internal.xml internal.xml.old
ファイルの中には Redis Sentinel のサーバーの Private IP が登録されています。
root@redissentinel-tokyo1:/etc/firewalld/zones#cat internal.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
<short>Internal</short>
<description>For use on internal networks. You mostly trust the other computers on the networks to not harm your computer. Only selected incoming connections are accepted.</description>
<service name="ssh"/>
<service name="mdns"/>
<service name="samba-client"/>
<service name="dhcpv6-client"/>
<service name="redis"/>
<service name="redis-sentinel"/>
<source address="192.168.198.87"/>
<source address="192.168.198.103"/>
<source address="192.168.198.112"/>
<forward/>
</zone>
以下の行を加えます。
<source address="192.168.139.199"/>
firewalld を再起動します。
firewall-cmd --reload
status を確認します。
root@redissentinel-tokyo1:/etc/firewalld/zones# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2023-06-30 08:59:35 UTC; 24s ago
Docs: man:firewalld(1)
Main PID: 29722 (firewalld)
Tasks: 2 (limit: 2234)
Memory: 21.7M
CPU: 958ms
CGroup: /system.slice/firewalld.service
└─29722 /usr/bin/python3 /usr/sbin/firewalld --nofork --nopid
Jun 30 08:59:35 redissentinel-tokyo1 systemd[1]: Starting firewalld - dynamic firewall daemon...
Jun 30 08:59:35 redissentinel-tokyo1 systemd[1]: Started firewalld - dynamic firewall daemon.
Redis クライアントから再度接続します。
root@redisclient:~# redis-cli -h redissentinel-tokyo1 --tls --cacert redissentinel-tokyo_ca.crt
redissentinel-tokyo1:6379>
エラーは表示されません。firewalld
の設定が有効化されていることが分かります。
redissentinel-tokyo1:6379> ping
(error) NOAUTH Authentication required.
ping では認証エラーが出ました。REDISCLI_AUTH
の設定漏れです。設定して再度トライします。
root@redisclient:~# export REDISCLI_AUTH='REDISのパスワードを設定してください'
root@redisclient:~# redis-cli -h redissentinel-tokyo1 --tls --cacert redissentinel-tokyo_ca.crt
redissentinel-tokyo1:6379> ping
PONG
読み込みと書き込みに成功しています。
redissentinel-tokyo1:6379> get scott
"tiger"
redissentinel-tokyo1:6379> set scott dixon
OK
redissentinel-tokyo1:6379> get scott
"dixon"
role コマンドで Master サーバーであることも再確認できます。
redissentinel-tokyo1:6379> role
1) "master"
2) (integer) 14510424
3) 1) 1) "192.168.198.112"
2) "6379"
3) "14510424"
2) 1) "192.168.198.103"
2) "6379"
3) "14510424"
firewalld の設定と再起動を他の2つのレプリカサーバーでも実行します。
最終的に全てのサーバーと接続できれば成功です。
root@redisclient:~# redis-cli -h redissentinel-tokyo2 --tls --cacert redissentinel-tokyo_ca.crt
redissentinel-tokyo2:6379> ping
PONG
redissentinel-tokyo2:6379> get scott
"dixon"
redissentinel-tokyo2:6379> quit
root@redisclient:~# redis-cli -h redissentinel-tokyo3 --tls --cacert redissentinel-tokyo_ca.crt
redissentinel-tokyo3:6379> ping
PONG
redissentinel-tokyo3:6379> get scott
"dixon"
まとめ
Akamai の cloud computing services を使って Redis Sentinel Cluster を容易に構築し、アプリケーションを想定した別のサーバーからアクセスもできました。また、firewalld の設定によってアクセス制御もできることもわかりました。