Redis Sentinel 構成の前に HAProxy を配置し常にマスターサーバーに接続できるようにする

Redis Sentinel はマスターサーバーの障害を検知し、動的にレプリカをマスターに昇格することできる高可用性ソリューションです。しかし、アプリケーションからの視点では一つ気になることがあります。アプリケーションからどうやってマスターサーバーの IP を知るかです。Redis Sentinel にはクライアントの構築についてドキュメントが公開されています。

https://redis.io/docs/reference/sentinel-clients/

この方法を使えば、Sentinel と通信することで、動的にマスターサーバーの IP を知ることができます。しかし、実際にはアプリケーションの仕様を変更したくないケースは多いです。本記事では HAProxy を利用して、アプリケーションの仕様変更を不要とし、常時マスターサーバーに接続できるようにする方法について説明します。

最終的には下記の構成を構築できます。
![redis-haproxy-final.jpg.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/d5454894-db03-4908-b261-ec57d9ac7099.jpeg)

:::note warn
今回紹介する例では、HAProxy が SPOF になります。HAProxyをクラスタ化し IP Sharing 機能を使うことで SPOF を排除できます。IP Sharing については以下の記事を参考にしてください。
:::
https://qiita.com/kabe-akam/items/a80f4a71358a27605076


# Redis Sentinel

Redis Sentinel の環境を用意します。今回は下記の記事で紹介した環境で行います。

https://qiita.com/110hideki/items/b816bf1bece1e8f5fef3

# アプリケーション (Redis Client) から見える Redis Sentinel
HAProxy を導入しないパターンを説明します。

最初にクライアントはマスターサーバーのIPを静的に保持して接続できています。
![redis-sentinel-1-first.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/a7dea2be-199f-c5d9-84c9-163e1b49c1bd.jpeg)

マスターサーバーがダウンし、クライアントがマスターサーバーに接続できないケースを考えます。
![redis-sentinel-2-serverdown.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/41f1751e-300a-ae8d-e2f1-0d8b9049d1cd.jpeg)

3 台のマスター・レプリカ構成を取っていた場合、レプリカのどちらがマスターになるかを知る必要があります。そのためには誰かが Sentinel か Redis に問い合わせする必要があります。
![redis-sentinel-3-masterchange.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/898ec6cb-73f7-7e44-4110-7eb4321c677d.jpeg)

本問題を解決するために本記事では HAProxy を使う例を紹介します。


# HAProxy を動作するインスタンスの準備

Linode を作成します。
- Tokyo Region
- Ubuntu 22.04 LTS
- Linode 2GB Plan 
- Private IP をオンにする (後からでも追加可能）
- Linode Label: haproxy-redis-tokyo
- Tags: Redis Sentinel と同じ

設定した Private IP をメモします。後で利用します。
```
localhost:~# ip -4 a show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 172.104.79.130/24 brd 172.104.79.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet {PUBLIC_IP_ADDRESS}/17 brd 192.168.255.255 scope global eth0
       valid_lft forever preferred_lft forever
```

インスタンスがセキュアになるように設定します。

https://www.linode.com/docs/products/compute/compute-instances/guides/set-up-and-secure/

Redis Server に接続できるように ``/etc/hosts`` に IP アドレスを登録します。
```
# BEGIN redis servers
# Redis
192.168.198.87 redissentinel-tokyo1 redis_1
192.168.198.103 redissentinel-tokyo2 redis_2
192.168.198.112 redissentinel-tokyo3 redis_3
# END redis servers
```
# Redis Server の設定

HAProxy がアクセスできるように firewalld の設定をします。

```
  <source address="{PUBLIC_IP_ADDRESS}"/>
```

最終的には全ての Redis Server が動作している Linux で設定する必要がありますが、まずは、マスターのサーバー環境で実施します。


```
systemctl restart firewalld
```

# HAProxy のインストール

www.linode.com のドキュメントを参照して、HAProxy をインストールします。

https://www.linode.com/docs/guides/how-to-use-haproxy-for-load-balancing/

```
apt update && apt upgrade
```

```
sudo apt-get install haproxy
```
インストールに成功したらバージョンを確認します。
```
haproxy-redis-tokyo:/etc/haproxy# haproxy -v
HAProxy version 2.4.22-0ubuntu0.22.04.1 2023/03/22 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2026.
Known bugs: http://www.haproxy.org/bugs/bugs-2.4.22.html
Running on: Linux 5.15.0-73-generic #80-Ubuntu SMP Mon May 15 15:18:26 UTC 2023 x86_64
```

# HAProxy の Config

``/etc/haproxy/`` にコンフィグファイルがあります。
```
haproxy-redis-tokyo:~# cd /etc/haproxy/
haproxy-redis-tokyo:/etc/haproxy# ls
errors  haproxy.cfg
```
``haproxy.cfg`` を確認します。このファイルに追記することになります。
```
haproxy-redis-tokyo:/etc/haproxy# cat haproxy.cfg
global
    log /dev/log	local0
    log /dev/log	local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

	# Default SSL material locations
	ca-base /etc/ssl/certs
	crt-base /etc/ssl/private

	# See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
	log	global
	mode	http
	option	httplog
	option	dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
	errorfile 400 /etc/haproxy/errors/400.http
	errorfile 403 /etc/haproxy/errors/403.http
	errorfile 408 /etc/haproxy/errors/408.http
	errorfile 500 /etc/haproxy/errors/500.http
	errorfile 502 /etc/haproxy/errors/502.http
	errorfile 503 /etc/haproxy/errors/503.http
	errorfile 504 /etc/haproxy/errors/504.http
```

## Redis 用の設定
以下の設定を追記します。この例ではマスターとして動作している redis_2 を登録する例です。
```
# Specifies TCP timeout on connect for use by the frontend ft_redis
# Set the max time to wait for a connection attempt to a server to succeed
# The server and client side expected to acknowledge or send data.
defaults REDIS
    mode tcp
    timeout connect 3s
    timeout server 6s
    timeout client 6s

# Specifies listening socket for accepting client connections using the default
# REDIS TCP timeout and backend bk_redis TCP health check.
frontend ft_redis
    bind *:6379 name redis
    default_backend bk_redis

# Specifies the backend Redis proxy server TCP health settings
# Ensure it only forward incoming connections to reach a master.
backend bk_redis
    server redis_6379 redis_2:6379 check inter 1s
```

## Stats ページのための設定
この設定を入れると HAProxy がフォワードする Redis サーバーの状態を表示できます。後ほど使用する例を紹介します。
```
#
listen stats
    mode http
    bind {HAproxy の Public IP}:7000
    stats uri /
    stats auth {ユーザー名}:{パスワード}
    stats refresh 10s
    stats show-legends
```

``stats auth`` には Stats にアクセスするためのクレデンシャルとなります。

:::note warn
使わないときはコメントアウトしてオフにしましょう。
:::


# redis-cli
設定を確認するために redis-cli を入手します。
```
apt install redis
```
エラーがでました。
```
haproxy-redis-tokyo:/etc/haproxy# apt install redis
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
E: Unable to locate package redis-cli
```
以下のコマンドの実行で解決できました。
```
add-apt-repository universe
```
再度インストールを試みます。
```
apt install redis
```

:::note warn
redis-server も同時にインストールされ、プロセスが起動します。不要なので停止してください。手順は後ほど説明します。
:::
インストールされたら、バージョンを確認します。
```
haproxy-redis-tokyo:~# redis-cli -v
redis-cli 6.0.16
```
redis-cli は TLS 接続する必要があるので、Redis Server の ``/etc/redis/tls/ca.crt`` をローカルのファイルにコピーします。
```
haproxy-redis-tokyo:/etc/haproxy# pwd
/etc/haproxy
haproxy-redis-tokyo:/etc/haproxy# ls -l tls
total 4
-r--r----- 1 haproxy haproxy 2029 Jul  1 02:49 redissentinel-tokyo_ca.crt
```
``REdISCLI_AUTH`` も環境変数に設定します。
```
export REDISCLI_AUTH=`Redis に接続するためのパスワード`
```
現在マスターが redis_2 のホストとして登録しているので、``-h`` で指定します。証明書は事前にコピーしたファイルを指定します。ここでは redis-cli の動作確認をするだけで、HAProxy 経由での接続確認ではありません。
```
haproxy-redis-tokyo:~# redis-cli -h redis_2 --tls --cacert /etc/haproxy/tls/redissentinel-tokyo_ca.crt
redis_2:6379> ping
PONG
```
PING PONG ができれば、認証された接続に成功しています。

書き込みができるかも確認します。
```
haproxy-redis-tokyo:~# redis-cli -h redis_2 --tls --cacert /etc/haproxy/tls/redissentinel-tokyo_ca.crt

redis_2:6379> get scott
"tiger"
redis_2:6379> set scott lion
OK
redis_2:6379> get scott
"lion"
```
scott のキーの値を変更できました。これは、クライアントがマスターサーバーに接続できているからです。


## HAProxy 上で Redis-server の停止
``redis-cli`` を使うために Redis をインストールしましたが、Redis サーバーが動いていると後ほど問題が起きる可能性がありますので、停止します。
```
systemctl stop redis-server
systemctl disable redis-server
```

実際に発生した問題は、HAProxy の Bind 設定との衝突です。今回は実施しませんが、HAProxy を冗長化したときに、redis-server が ``6379`` ポートを Listen していると、次のような bind 設定がエラーとなって HAProxy が起動できません。

```
bind *:6379
```
そのため、特定の IP を指定する必要がありました。例えば次のように設定する必要がありました。
```
bind {Server の IP address}:6379
```
このように設定することで問題は解消されるのですが、別の記事で紹介する ``keepalive`` を使った VIP の設定では、バックアップとして動作するサーバー側ではその VIP が動いていないので、HAProxy 起動時に VIP でバインドすることができません。よって ``keepalived`` でフェールオーバーしても、VIP にバインドされていないので HAProxy につなぐことができませんでした。これも HAProxy で ``redis-server`` を停止することで ``bind *:6379`` のように設定も楽になり問題も解消されます。


# HAProxy に監視の機能を入れる
## external-check
HAProxy の ``external-check`` は外部のコマンドを起動してステータス監視をするときに便利な機能です。この機能を利用し、スクリプトを登録します。スクリプトの中では、以下のコマンドを起動し、どのサーバーがマスターなのかを常に監視します。

:::note
``tcp-check`` を使う方法もありますが、TLS で接続する必要があるため、``external-check`` を使います。
:::

```
haproxy-redis-tokyo:~# /usr/bin/redis-cli --no-auth-warning -a $password -h redis_1 -p 6379 --tls --cacert /etc/haproxy/tls/redissentinel-tokyo_ca.crt INFO REPLICATION | egrep role
role:slave

haproxy-redis-tokyo:~# /usr/bin/redis-cli --no-auth-warning -a $password -h redis_2 -p 6379 --tls --cacert /etc/haproxy/tls/redissentinel-tokyo_ca.crt INFO REPLICATION | egrep role
role:master
```
exernal_check で指定するスクリプトを配置します。
```
haproxy-redis-tokyo:/etc/haproxy# ls -l bin
total 4
-rwxr-x--- 1 haproxy haproxy 459 Jul  1 12:52 check_redis_master.sh
```

external-check で起動されるスクリプトです。
```
#!/bin/bash
password='YOUR_REDIS_SERVER_PASSWORD'
ip_adr=$(echo $@ | awk '{print$3}')
command='INFO REPLICATION'
redis_server_role=$(/usr/bin/redis-cli --no-auth-warning -a $password -h $ip_adr -p 6379 --tls --cacert /etc/haproxy/tls/redissentinel-tokyo_ca.crt $command | grep role | awk -F ':' '{print $2}' | tr -d '\r')

if [[ $redis_server_role == 'master' ]]; then
        exit 0
else
        exit 1
fi
```

## haproxy.cfg

haproxy.cfg の global を次のように変更します。``insecure-fork-wanted``、``insecure-setuid-wanted``、``external-check`` を追記します。
```
global
    insecure-fork-wanted
    insecure-setuid-wanted
	external-check
	log /dev/log	local0
	log /dev/log	local1 notice
#	chroot /var/lib/haproxy
	stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
	stats timeout 30s
	user haproxy
	group haproxy
	daemon
```

backend の設定を次のように ``external-check`` を使うように設定します。
```
# Specifies the backend Redis proxy server TCP health settings
# Ensure it only forward incoming connections to reach a master.
backend bk_redis
    option external-check
    external-check path "/usr/bin:/bin:/usr/local/bin"
    external-check command /etc/haproxy/bin/check_redis_master.sh
    server redis_6379 redis_2:6379 check inter 10s
```
HAProxy を再起動します。
```
systemctl restart haproxy
```
``/var/log/haproxy.log`` には redis_2 に対してステータスを確認しているログが表示されています。
```
haproxy-redis-tokyo:/etc/haproxy# tail -f /var/log/haproxy.log
Jul  1 04:22:33 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:22:33.071] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:22:43 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:22:43.143] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:22:53 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:22:53.255] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:23:03 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:23:03.337] stats stats/<STATS> 0/0/0/0/0 200 17810 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:23:13 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:23:13.435] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:23:23 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:23:23.539] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:23:33 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:23:33.626] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:23:43 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:23:43.698] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:23:53 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:23:53.802] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:24:03 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:24:03.879] stats stats/<STATS> 0/0/0/0/0 200 17810 - - LR-- 2/2/0/0/0 0/0 "GET / HTTP/1.1"
Jul  1 04:24:13 haproxy-redis-tokyo haproxy[15891]: XX.XX.XX.XX:64282 [01/Jul/2023:04:24:13.954] stats stats/<STATS> 0/0/0/0/0 200 17812 - - LR-- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
```

redis-cli も動作しています。
```
haproxy-redis-tokyo:~# redis-cli -h redis_2 --tls --cacert /etc/haproxy/tls/redissentinel-tokyo_ca.crt
redis_2:6379> ping
PONG
redis_2:6379> get scott
"lion"
redis_2:6379> set dixson
(error) ERR wrong number of arguments for 'set' command
redis_2:6379> set scott dixson
OK
redis_2:6379> get scott
"dixson"
redis_2:6379> quit
```


## Stats
``http://{HAProxy サーバーの PublicIP}:7000/`` にアクセスします。次のようなページが表示されます。まずは、表示されたことを確認してください。``haproxy.cfg`` の ``auth`` で指定したユーザー名とパスワードを入力してください。

![haproxy-status.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/f799e06e-6151-9ef6-c604-705e450e6ff8.jpeg)

次に ``haproxy.cfg`` に全ての Redis サーバーを登録します。次のように書き換えます。

```
変更前
server redis_6379 redis_2:6379 check inter 10s
```

```
変更後
server redis_6379_1 redis_1:6379 check inter 1s
server redis_6379_2 redis_2:6379 check inter 1s
server redis_6379_3 redis_3:6379 check inter 1s
```

:::note warn
Redis Server の Firewall 設定も忘れないでください。
:::

HAProxy をリスタートします。

```
systemctl restart haproxy
```
Stat をブラウザで見ます。bk_redis の表に３つのサーバーの状態が見えます。
![haproxy-status-3node.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/9e47a67b-07b4-075f-5868-b03ce0366d5e.jpeg)
マスターとレプリカはそれぞれ、緑と赤で表示されています。レプリカのサーバーは実際には落ちているわけではなく、先程登録した ``external-check`` で動いているスクリプトでステータス ``1`` で返るようにしているからです。HAProxy からはステータス ``0`` で返るマスターサーバーが有効としてフォワードしています。


# Master の切り替え
## HAProxy サーバーのクライアントからの確認
マスターとして動作している Redis_2 のサーバーを止めます。
```
systemctl stop redis-server
```

Stats では一瞬全てが赤のステータスになります。
![haxproxy-status-masterdown.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/bb86122e-bc1b-87a5-60d8-8cd086e1fb9c.jpeg)


HAProxy のホストの Redis-cli を使って接続します。接続されたサーバーは role:master となっています。
```
haproxy-redis-tokyo:~# redis-cli --tls --cacert  redissentinel-tokyo_ca.crt info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.198.87,port=6379,state=online,offset=29561919,lag=1
master_failover_state:no-failover
master_replid:a284a16594fa8ce12b0db3b2d52eb4a185132ed5
master_replid2:4831258c3aa4c7d8d6c9e0eb1244acb86c511c8a
master_repl_offset:29562064
second_repl_offset:29497534
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:28493428
repl_backlog_histlen:1068637
```
最終的には、以下のように HAProxy は Redis_3 にフォワードしています。
![redis_haproxy-failover.jpg.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/50104b99-14c4-8e2f-10f3-608119008859.jpeg)


Stats は以下のように見えます。Redis_3 が緑色になっています。
![haproxy-status-3takesmasterrole.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/07aa239e-e071-ec4d-a0e2-4bfce0386496.jpeg)


## Redis Client アプリケーションからの接続
先程までは、HAProxy のサーバー内から接続していましたが、ここからはリモートにある Redis Client から接続を確認します。
![redis-haproxy-client.jpg.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/ea7b40a9-3f9a-ba0c-a412-176f0d37898c.jpeg)


``/etc/hosts`` に HAProxy の Private IP を登録します。

```
{PUBLIC_IP_ADDRESS} redis-haproxy
```

``REDISCLI_AUTH`` 環境変数をセットします。Redis Sentinel がインストールされたときに作成されたユーザーのホームディレクトリ配下に作成された ``deployment-secrets.txt`` に記載されている redis password が該当します。

HAproxy に接続します。
```
redisclient:~# redis-cli -h redis-haproxy --tls --cacert redissentinel-tokyo_ca.crt ping
PONG
```

HAProxy経由では必ず Master ロールのサーバーに接続されます。
```
redisclient:~# redis-cli -h redis-haproxy --tls --cacert redissentinel-tokyo_ca.crt info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.198.87,port=6379,state=online,offset=29619571,lag=1
master_failover_state:no-failover
master_replid:a284a16594fa8ce12b0db3b2d52eb4a185132ed5
master_replid2:4831258c3aa4c7d8d6c9e0eb1244acb86c511c8a
master_repl_offset:29619585
second_repl_offset:29497534
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:28554748
repl_backlog_histlen:1064838
```

```
redisclient:~# redis-cli -h redis-haproxy --tls --cacert redissentinel-tokyo_ca.crt role
1) "master"
2) (integer) 29621755
3) 1) 1) "192.168.198.87"
      2) "6379"
      3) "29621321"
```

止めていた Redis_2 の redis-server を起動します。
```
redissentinel-tokyo2:~# systemctl start redis-server
```

マスターではなくレプリカとして起動していることも分かります。
```
haproxy-redis-tokyo:~# /usr/bin/redis-cli --no-auth-warning -a $password -h redis_2 -p 6379 --tls --cacert /etc/haproxy/tls/redissentinel-tokyo_ca.crt INFO REPLICATION | egrep role
role:slave
```
![redsi-haproxy-client-allup.jpg.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/dc6b0d8b-88b1-d300-1182-ad22508ede1f.jpeg)



## マスターサーバーの停止

Redis Client で redis-cli を HAproxy に接続した状態にします。
```
redisclient:~# redis-cli -h redis-haproxy --tls --cacert redissentinel-tokyo_ca.crt
redis-haproxy:6379> ping
PONG
redis-haproxy:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.198.87,port=6379,state=online,offset=29954946,lag=0
slave1:ip=192.168.198.103,port=6379,state=online,offset=29954946,lag=0
master_failover_state:no-failover
master_replid:a284a16594fa8ce12b0db3b2d52eb4a185132ed5
master_replid2:4831258c3aa4c7d8d6c9e0eb1244acb86c511c8a
master_repl_offset:29955235
second_repl_offset:29497534
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:28902228
repl_backlog_histlen:1053008
```


マスターとして動作している Redis_3 を停止します。
```
redissentinel-tokyo3:~# systemctl stop redis-server
```
下図の状態になります。
![redis-haproxy-redis3-down.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/c84cda2f-4bd4-c65a-1fed-26ff8a921d83.jpeg)


マスターが変わったことを確認します。今回再度 Redis_2 がマスターになりました。
![redis-master-switch-from3to2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/3280d960-8db7-1b6e-8892-7b650fe76e8c.jpeg)

Redis Client にて redis-cli で接続した状態から再度コマンドを実行します。
```
redis-haproxy:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.198.87,port=6379,state=online,offset=29971306,lag=1
master_failover_state:no-failover
master_replid:fbb1e8bf9574889409d0bdfdcb78d4d56387877b
master_replid2:a284a16594fa8ce12b0db3b2d52eb4a185132ed5
master_repl_offset:29971306
second_repl_offset:29967061
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:29765770
repl_backlog_histlen:205537
redis-haproxy:6379> role
1) "master"
2) (integer) 29974806
3) 1) 1) "192.168.198.87"
      2) "6379"
      3) "29974806"
```
redis-cli は接続した状態でマスターの IP が変更されていることが分かります。

![redis-haproxy-client-failover-again.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264188/9e480001-97a1-bb97-1bff-4f3e1775bfe6.jpeg)

Redis-server のマスターがダウンしたときにログやファイルにどのように記録されているかは下記を参考にしてください。

https://qiita.com/110hideki/items/ea112ac86bc89da3355e


# まとめ

Redis Sentinel と HAProxy  を使うことで、Redis Server の高可用性を保ちながら、アプリケーションは常に Redis のマスターサーバーに接続できることを確認しました。

HAProxy を H/A 構成にすれば、SPOF を排除できますので、以下の記事も参考にしてください。

https://qiita.com/kabe-akam/items/5e1ef751b8badf454f94